Compare commits

..

335 Commits

Author SHA1 Message Date
sakridge
563231132f Stake program update (#15308) 2021-02-12 17:15:48 -08:00
mergify[bot]
32ec9147bb Rework spl_token_v2_self_transfer_fix to avoid any SPL Token downtime (#15306)
(cherry picked from commit 2e7aebf0bb)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-02-12 23:59:08 +00:00
mergify[bot]
4be8842925 Upgrade to SPL Token 3.1.0 program binary (#15302)
(cherry picked from commit aa97da2146)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-02-12 23:27:30 +00:00
mergify[bot]
b1ef9045ec docs: getLargestAccounts caching notice (#15293) (#15295)
(cherry picked from commit 760e163190)

Co-authored-by: Josh <josh.hundley@gmail.com>
2021-02-12 18:43:56 +00:00
publish-docs.sh
dbe4d87e60 Fix registration link 2021-02-11 21:54:00 -07:00
mergify[bot]
d2efa3aa15 RPC documentation updates for token deltas / blockTimes in getConfirmedSignatures2/getConfirmedTransaction (#14871) (#15284)
* docs: add token balances response info

* docs: add blockTime to getConfirmedSignatures and getConfirmedTransaction

* docs: update example responses

* fix: remove space

(cherry picked from commit 6b8e710988)

Co-authored-by: Josh <josh.hundley@gmail.com>
2021-02-12 02:13:32 +00:00
mergify[bot]
ccd2c6cc13 Add per-byte logging cost (#15279) (#15282)
(cherry picked from commit 6650fbf443)

Co-authored-by: Jack May <jack@solana.com>
2021-02-12 02:09:45 +00:00
mergify[bot]
e976b1547a Fix flaky test test_concurrent_snapshot_packaging (#15252) (#15281)
(cherry picked from commit 990bb426a9)

Co-authored-by: carllin <carl@solana.com>
2021-02-12 01:22:06 +00:00
mergify[bot]
03ac807756 RPC: add caching to getLargestAccounts (#15154) (#15271)
* introduce get largest accounts cache

* remove cache size and change hash key

* remove eq and hash derivation from commitment config

* add slot to the cache

(cherry picked from commit 4013f91dbe)

Co-authored-by: Josh <josh.hundley@gmail.com>
2021-02-11 21:13:09 +00:00
mergify[bot]
067871cc39 Clean up mainnet-beta inflation candidate features (#15257)
(cherry picked from commit 47c60f8e98)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-02-11 03:02:16 +00:00
mergify[bot]
e9ceb99460 Match BPF instruction reporting to dump file (#15254) (#15256)
(cherry picked from commit 10abd199e1)

Co-authored-by: Jack May <jack@solana.com>
2021-02-11 02:52:25 +00:00
Michael Vines
cd994f0162 Bump version to 1.5.7 2021-02-10 05:18:39 +00:00
mergify[bot]
01e4d0a1e9 Use spl-token-mint secondary index for relevant getProgramAccounts requests (#15219) (#15224)
(cherry picked from commit 948819dfa8)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-02-10 00:39:55 +00:00
mergify[bot]
7f0f43cb28 Warp timestamp and extend max-allowable-drift for accommodate slow blocks (#15204) (#15222)
* Remove timestamp_correction feature gating

* Remove timestamp_bounding feature gating

* Remove unused deprecated ledger code

* Remove unused deprecated unbounded-timestamp code

* Enable independent adjustment of fast/slow timestamp bounding

* Update timestamp bounds to 25% fast, 80% slow; warp timestamp

* Update bank hash test

* Add PR number to feature

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

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

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-02-10 00:03:26 +00:00
mergify[bot]
d0bf97d25d uses btree-map instead of hash-map for cluster-slots (#15194) (#15220)
retain traverses all values in the hashmap which is slow:
https://github.com/solana-labs/solana/blob/88f22c360/core/src/cluster_slots.rs#L45
btree-map instead allows more efficient prunning there.

In addition there is potential race condition here:
https://github.com/solana-labs/solana/blob/88f22c360/core/src/cluster_slots.rs#L68-L74
If another thread inserts a value at the same slot key between the read
and write lock, current thread will discard the inserted value.

(cherry picked from commit 2758588ddd)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-02-09 23:21:08 +00:00
Michael Vines
c3056734e3 solana-test-validator now uses the BPF JIT by default, --no-bpf-jit to disable 2021-02-09 21:43:00 +00:00
mergify[bot]
5e2b9e595d use index version of calculating hash (#15189) (#15211)
* use index version of calculating hash

* invert const

* formatting

(cherry picked from commit 8424fe2c12)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-02-09 18:02:23 +00:00
mergify[bot]
9be3e00546 Add cli deploy tests (bp #15116) (#15147)
* Add cli deploy tests (#15116)

(cherry picked from commit 210514b136)

* fix conflicts

Co-authored-by: Jack May <jack@solana.com>
2021-02-09 05:42:43 +00:00
mergify[bot]
0c2dcd759c Parse upgradeable loader instructions and accounts (#15195) (#15199)
* Parse upgradeable-loader instructions

* Parse upgradeable-loader accounts

(cherry picked from commit c0a6272afd)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-02-09 01:47:46 +00:00
mergify[bot]
b711476811 removes locked pubkey references (#15152) (#15182)
(cherry picked from commit b6f231b60e)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-02-08 03:24:38 +00:00
mergify[bot]
e4fe7dfbbd Add jit and caching args to ledger-tool (#15177) (#15178)
(cherry picked from commit 11b84cb870)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-02-06 21:04:46 +00:00
mergify[bot]
40e62c60d3 Require lockup authority to change withdraw authority on locked stake (#14861) (#15170)
(cherry picked from commit dc7041ba07)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-02-06 08:27:25 +00:00
Jon Cinque
a93d37b804 program-test: Add warp tests for rent and stake rewards (#15136)
* program-test Add rent collection and stake rewards

* Improve tests to initialize vote state

* Update comment

* Update program-test/src/lib.rs

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

* Review feedback

* cargo fmt

* Avoid using hard-coded slots in tests

* Make genesis_config private

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-02-05 23:39:12 -08:00
Jon Cinque
65e6df2b0d program-test: Add ability to warp to the future (#14998)
* program-test: Add ability to warp to the future

* Make `start_local_server` take by value

* Remove clear_invoke_context
2021-02-05 23:39:12 -08:00
Jon Cinque
f02bd10d4a program-test: Set context without panic (#14997)
* program-test: Fix CPI and multiple instructions

* Whitespace

* Add CPI test in program-test
2021-02-05 23:39:12 -08:00
Michael Vines
d7d8a751d9 Increment hyper versions to pacify cargo audit (#15172) 2021-02-05 23:13:16 -08:00
mergify[bot]
f6f4193d4d Only publish release-tag docs on beta channel (#15158) (#15168)
(cherry picked from commit 819d829c41)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-02-06 06:59:09 +00:00
publish-docs.sh
fe0077d88a Update slashing roadmap link 2021-02-05 16:29:44 -07:00
mergify[bot]
8016f61ce8 use thread pool for non-index hash calculations (#15149) (#15153)
(cherry picked from commit fabecdc86c)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-02-05 21:59:59 +00:00
mergify[bot]
0b6366da9c sentinel value for zero lamport accounts in hash scanning (#15097) (#15145)
* sentinel value for zero lamport accounts in hash scanning

* fix test

(cherry picked from commit f85be6259b)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-02-05 15:16:11 -06:00
mergify[bot]
d567a62cc7 caches descendants in bank forks (#15107) (#15148)
(cherry picked from commit 6fd5ec0e4c)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-02-05 19:38:36 +00:00
mergify[bot]
eccea2b1ea Add w3m's inflation pubkeys (#15142) (#15144)
(cherry picked from commit 2a60dd8492)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-02-05 08:59:26 -08:00
Michael Vines
bfd93cc13f Sort inflation candidates alphabetically 2021-02-05 00:07:46 -08:00
mergify[bot]
b21c89e494 Warn lastValidSlot with some terminology tweaks (#15081) (#15122)
* Warn lastValidSlot with some terminology tweaks

* Apply suggestions from code review

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

* Restore previous arrangment of slot def. and tweak upon it

* Apply suggestions from code review

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

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

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-02-05 07:07:00 +00:00
mergify[bot]
253b68abf1 Inflation Nomination for sotcsa (#15105) (#15120)
(cherry picked from commit e908a4b3fc)

Co-authored-by: sotcsa <sotcsa@users.noreply.github.com>
2021-02-04 21:49:51 -08:00
mergify[bot]
49034b8016 nit: cleanup feature status display (#15113) (#15117)
* nit: cleanup feature status display

* nudge

(cherry picked from commit a52a241852)

Co-authored-by: Jack May <jack@solana.com>
2021-02-05 05:38:38 +00:00
mergify[bot]
3838fb62d4 move timer end outside if (#15087) (#15114)
(cherry picked from commit f0d58f5549)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-02-04 20:12:56 -08:00
mergify[bot]
9f267fc5e7 remove unused arg from function (#15096) (#15115)
(cherry picked from commit 7d9f5ad525)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-02-04 20:12:31 -08:00
mergify[bot]
5a82265650 deploy doc updates (#15109) (#15112)
(cherry picked from commit 82350f9350)

Co-authored-by: Jack May <jack@solana.com>
2021-02-05 00:52:26 +00:00
mergify[bot]
77d2ed95ff Add ref count from storage (#15078) (#15092)
(cherry picked from commit e5225b7e68)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-02-04 15:12:23 -08:00
mergify[bot]
858ca752e2 Generate keypair file for c program deployment (#15080) (#15110)
* Generate keypair file for c program deployment

* Build and use solana-keygen in test-stable-perf

(cherry picked from commit bba1b49663)

Co-authored-by: Jack May <jack@solana.com>
2021-02-04 23:02:01 +00:00
mergify[bot]
fea0bd234c Fix pubkey refcount for shrink + clean (#14987) (#15108)
(cherry picked from commit e4d0d4bfae)

Co-authored-by: carllin <wumu727@gmail.com>
2021-02-04 22:11:57 +00:00
mergify[bot]
7af7d5f22c Add LowFeeValidation Nomination (#15098) (#15102)
(cherry picked from commit 53dab29528)

Co-authored-by: bonsfi <bonsfi@users.noreply.github.com>
2021-02-04 11:06:29 -08:00
mergify[bot]
de4cccd977 Enable inflation candidate for RockX (#15099) (#15101)
(cherry picked from commit c6f572c331)

Co-authored-by: calvinzhou-rockx <55546839+calvinzhou-rockx@users.noreply.github.com>
2021-02-04 10:50:04 -08:00
mergify[bot]
9f74136632 borrow storages (#15088) (#15095)
(cherry picked from commit f49a70e626)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-02-04 18:43:15 +00:00
mergify[bot]
21484acc20 Inflation Nomination for Diman (#15083) (#15091)
(cherry picked from commit d87e0c3f1d)

Co-authored-by: DimAn <71597545+diman-io@users.noreply.github.com>
2021-02-04 09:39:14 -08:00
mergify[bot]
36ad03af1f calculate hash from store instead of index (bp #15034) (#15084)
* calculate hash from store instead of index (#15034)

* calculate hash from store instead of index

* restore update hash in abs

(cherry picked from commit 600ff0d915)

* fix merge conflict (#15085)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-02-04 16:58:11 +00:00
mergify[bot]
e255ee52b1 Nomination candidate for p2pvalidator (#15079) (#15090)
(cherry picked from commit 2ed074ba2a)

Co-authored-by: rk-p2p <56305239+rk-p2p@users.noreply.github.com>
2021-02-04 08:55:18 -08:00
mergify[bot]
972540907b Don't load all accounts into memory for capitalization check (#14957) (#15072)
* Don't load all accounts into memory for capitalization check

Co-authored-by: carllin <carl@solana.com>
2021-02-04 11:49:48 +00:00
mergify[bot]
cfeed09f1f Add program deployment docs (#15075) (#15082)
(cherry picked from commit d0118a5c42)

Co-authored-by: Jack May <jack@solana.com>
2021-02-04 10:42:37 +00:00
mergify[bot]
dadebb2bba Don't reset accounts if the remove_account comes from a clean (#15022) (#15066)
Store may be in-use with a snapshot creation, so don't disturb
it's state.

Co-authored-by: sakridge <sakridge@gmail.com>
2021-02-04 06:02:02 +00:00
mergify[bot]
169403a15e removes pubkey references (#15050) (#15073)
(cherry picked from commit 86467d825a)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-02-04 00:24:58 +00:00
mergify[bot]
e2a874370b Cleanup v1 shrink path (#15009) (#15071)
move legacy functions to another impl block

(cherry picked from commit 37aac5a12d)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-02-03 23:33:21 +00:00
mergify[bot]
baf7713744 Fix integer overflow in degenerate invoke_signed BPF syscalls (#15051) (#15069)
(cherry picked from commit ebbaa1f8ea)

Co-authored-by: Mrmaxmeier <Mrmaxmeier@gmail.com>
2021-02-03 23:04:03 +00:00
mergify[bot]
573304cf73 Fix which shared object the test uses (#15060) (#15068)
(cherry picked from commit 02a5f7104a)

Co-authored-by: Jack May <jack@solana.com>
2021-02-03 22:49:55 +00:00
mergify[bot]
ec6d5933de Revert hard nofile limit back to 500000 (#15061)
(cherry picked from commit 42bf6dc2ab)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-02-03 13:49:54 -08:00
mergify[bot]
30b815e7bc Correct stakeconomy::vote::id() (#15062) (#15065)
(cherry picked from commit c3ba70300b)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-02-03 12:41:53 -08:00
mergify[bot]
f463ebfde2 Upgradeable loader max_data_len limit (#15039) (#15057)
(cherry picked from commit d24d5fba0e)

Co-authored-by: Jack May <jack@solana.com>
2021-02-03 18:34:06 +00:00
Michael Vines
ba0aa706e4 Avoid panic when the release cache is empty 2021-02-03 09:32:57 -08:00
Jack May
eacf9209f7 update transaction.md 2021-02-03 09:03:02 -08:00
mergify[bot]
ba12a14494 Nomination candidate for buburuza (#15047) (#15055)
(cherry picked from commit f2d415cf13)

Co-authored-by: buburuza27 <78487355+buburuza27@users.noreply.github.com>
2021-02-03 08:41:51 -08:00
mergify[bot]
4e60f95854 Don't squash caught errors, please (#15046) (#15049)
* Don't squash caught errors, please

* Update blockstore.rs

* Update blockstore.rs

(cherry picked from commit 8376781ec8)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-02-03 16:33:53 +00:00
mergify[bot]
a7193ce834 adds flag to disable duplicate instance check (#15006) (#15053)
(cherry picked from commit 0ad063f4e9)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-02-03 08:33:07 -08:00
mergify[bot]
f12a467177 transaction-history -v now shows the transaction timestamp if available (#15052)
(cherry picked from commit 971c222cf7)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-02-03 08:31:34 -08:00
mergify[bot]
45a92337f4 bump rust-bpf-sysroot to v0.14 (#15040) (#15045)
(cherry picked from commit 286e4d6924)

Co-authored-by: Jack May <jack@solana.com>
2021-02-03 13:03:25 +00:00
mergify[bot]
bfa6e9bdf6 Nomination candidate for bunghi (#15036) (#15044)
* Update feature_set.rs

* Update feature_set.rs

* Update sdk/src/feature_set.rs

* Update feature_set.rs

* Update sdk/src/feature_set.rs

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

Co-authored-by: bunghi <31234197+bunghi@users.noreply.github.com>
2021-02-03 11:41:37 +00:00
mergify[bot]
a7d9a52690 cli: add command to dump the upgradeable program to a file (#15029) (#15035)
(cherry picked from commit 9c6d899efb)

Co-authored-by: Jack May <jack@solana.com>
2021-02-03 10:22:29 +00:00
mergify[bot]
4b3391f1d8 Cli: some moniker follow-up (#14981) (#15038)
* Enable monikers in config set

* Fixup websocket compute

(cherry picked from commit 38e2fe8997)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-02-03 09:25:10 +00:00
mergify[bot]
19b203f344 cli: add query command to solana program (bp #15017) (#15028)
* cli: add query command to solana program (#15017)

(cherry picked from commit 6cf6ef3a32)

# Conflicts:
#	cli-output/src/cli_output.rs
#	cli/src/program.rs

* fix conflicts

Co-authored-by: Jack May <jack@solana.com>
2021-02-03 08:04:18 +00:00
Michael Vines
6150faafb6 Adapt create-snapshot to avoid triggering recent internal bank sanity checks
(cherry picked from commit 709aa74e11)
2021-02-02 23:22:01 -08:00
Trent Nelson
49e608295e docs: bump nofiles recommendations to match maps
(cherry picked from commit 894b412aef)
2021-02-02 23:21:24 -08:00
mergify[bot]
636be95e2a CLI: Move solana validators summary to end of output (#15033)
(cherry picked from commit 31d30bb5e8)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-02-03 06:36:47 +00:00
mergify[bot]
0db5a74bb9 streamline calculate_accounts_hash (#14980) (#15015)
Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-02-03 05:31:25 +00:00
mergify[bot]
08fd4905db remove legacy merkle root (bp #14772) (#15021)
* remove legacy merkle root (#14772)

* remove legacy merkle root
f78197a

* clippy

* compile error

* borrow error

* derministic results

* clippy

* borrow

(cherry picked from commit 1b85114a9c)

# Conflicts:
#	merkle-root-bench/src/main.rs
#	runtime/src/accounts_db.rs

* remove legacy merkle root (#14772)

* remove legacy merkle root
f78197a

* clippy

* compile error

* borrow error

* derministic results

* clippy

* borrow

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-02-03 03:19:28 +00:00
mergify[bot]
3610b6f31c cli: Don't overallocate upgradeable program if --final specified (#15011) (#15027)
(cherry picked from commit a1b9e00c14)

Co-authored-by: Jack May <jack@solana.com>
2021-02-03 03:09:27 +00:00
mergify[bot]
b35f35a7e8 keygen: Improve messaging around BIP39 passphrase usage (#15026)
(cherry picked from commit 53423c99aa)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-02-03 02:09:20 +00:00
mergify[bot]
790a6b7550 CLI: Surface account query errors (#15024)
(cherry picked from commit 3abb39c04f)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-02-03 01:59:59 +00:00
mergify[bot]
30d2e15945 speed up merkle root calculation (bp #14710) (#15020)
* speed up merkle calculation (#14710)

(cherry picked from commit 18bd0c9a5b)

* back port crate versions for merkle-root-bench

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
Co-authored-by: Jeff Washington (jwash) <wash678@gmail.com>
2021-02-02 19:39:49 -06:00
mergify[bot]
7b3c7a075a Allow passing buffer by keypair to cli program deploy (#15010) (#15016)
(cherry picked from commit 7831428e82)

Co-authored-by: Jack May <jack@solana.com>
2021-02-02 22:49:09 +00:00
mergify[bot]
f534698618 CLI: Add sigverify results to solana decode-transaction output (bp #14964) (#15008)
* cli-output: Add option sigverify status to `println_transaction()` output

(cherry picked from commit a2aea0ca33)

* cli: Add sigverify status to `decode-transaction` output

(cherry picked from commit d547585041)

* CLI: Modernize `decode-transaction` about message

(cherry picked from commit fddbfe1052)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-02-02 20:33:24 +00:00
mergify[bot]
fe1347b441 Clean up some old commitment names (#14994) (#15003)
(cherry picked from commit 2780214e71)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-02-02 18:48:19 +00:00
mergify[bot]
8f6c01f0f8 Add Hackathon banner (#15004) (#15005)
(cherry picked from commit b57f33948d)

Co-authored-by: R. M. Shea <8948187+rmshea@users.noreply.github.com>
2021-02-02 09:46:47 -07:00
mergify[bot]
066ff36175 Disable AppendVec warn! for now (#14996) (#15001)
* Disable AppendVed warn! for now

* Fix version...

* Update append_vec.rs

(cherry picked from commit 31168fe343)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-02-02 16:09:49 +00:00
mergify[bot]
5da9e7cb8a Parse SPL Memo v3 (#14979) (#14989)
* Parse memo v3 too

* tree

(cherry picked from commit 34dfcc9c6f)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-02-01 23:16:01 -07:00
Brian Long
09b68f2fbb Inflation Nomination for BL (#14972)
(cherry picked from commit 8e0fdff17c)
2021-02-01 21:00:15 -08:00
mergify[bot]
d9fcd84bc2 Add validator flag to opt in to cpi and logs storage (bp #14922) (#14973)
* Add validator flag to opt in to cpi and logs storage (#14922)

* Add validator flag to opt in to cpi and logs storage

* Default TestValidator to opt-in; allow using in multinode-demo

* No clone

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

* TestValidator store cpi and logs

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-02-02 02:51:35 +00:00
Trent Nelson
86703384dc cli: Improve stake-history output readability 2021-02-02 02:45:23 +00:00
Trent Nelson
580b0859e8 cli-output: Minor refactor of build_balance_message() 2021-02-02 02:45:23 +00:00
Michael Vines
5d8c5254b0 Add "init" subcommand
(cherry picked from commit 49c908dc50)
2021-02-01 17:05:00 -08:00
Leopold Schabel
ea83292daa Certus One inflation enablement feature pair (#14961)
(cherry picked from commit c06568f3db)
2021-02-01 17:00:18 -08:00
Eric Williams
f1c3e6dc36 Update economics docs (#14965)
* clarified inflation split and equation

* clarify staking yield description
2021-02-01 22:40:00 +00:00
mergify[bot]
bdd19c09d1 More rich runtime logging (#14938) (#14967) 2021-02-01 14:26:31 -08:00
Michael Vines
95cbfce900 Update sdk/src/feature_set.rs
(cherry picked from commit e0f6695cc2)
2021-02-01 08:12:12 -08:00
Stakeconomy.com
a404a9d802 Update feature_set.rs
(cherry picked from commit 4ba9e39941)
2021-02-01 08:12:12 -08:00
Michael Vines
15cd1283e8 Template for an Inflation Candidate nomination
To submit your nomination:
1. Replace all instances of "my_name" with a suitable alternative then address the "TODO" code comments
2. Submit a new Github pull request and work with the project contributors to merge your pull request

(cherry picked from commit 15baf43d1e)
2021-02-01 08:12:12 -08:00
mergify[bot]
512a193674 Use helper for count() in accountsDB (#14953) (#14956)
(cherry picked from commit 63c44bd690)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-01-31 18:23:01 -08:00
Michael Vines
de37795ca1 /i/o/ 2021-01-31 08:22:23 -08:00
nampdn
cb7871347d style(spacing): reformat tab spacing
(cherry picked from commit f98889adc0)
2021-01-30 08:36:14 -08:00
Michael Vines
b4b9ea7771 Template for an Inflation Candidate nomination
To submit your nomination:
1. Replace all instances of "my_name" with a suitable alternative then address the "TODO" code comments
2. Submit a new Github pull request and work with the project contributors to merge your pull request

(cherry picked from commit a7ff1684f5)
2021-01-30 08:36:14 -08:00
Trent Nelson
62b7bf5365 CLI: Reinstate logging, disabled by default
(cherry picked from commit a44392048d)
2021-01-29 21:46:58 -08:00
mergify[bot]
91c57cd70d Add generalized voting process to enable full inflation (bp #14702) (#14732)
* Add generalized voting process to enable full inflation

(cherry picked from commit 072e5e54d8)

* Update feature_set.rs

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-01-30 03:19:19 +00:00
Michael Vines
cb35fc185b Garbage collect old releases
(cherry picked from commit ea4f516f84)
2021-01-29 18:37:43 -08:00
Michael Vines
cca9009f23 Help capitalization fixes
(cherry picked from commit 9e3c130ac9)
2021-01-29 18:37:43 -08:00
Ryo Onodera
d8d73ff56c Clean up VerifiedVotePackets (#14822)
(cherry picked from commit bd0433c373)
2021-01-29 18:03:41 -08:00
Jack May
34504797b4 Richer runtime failure logging (#14875)
(cherry picked from commit 0b1015f7d3)
2021-01-29 18:03:33 -08:00
sakridge
1767e4fbde Increase vm map limit recommendation (#14892)
Give some more buffer from 400k

(cherry picked from commit 84e52b6065)
2021-01-29 18:03:03 -08:00
sakridge
39515cae5e Use already-generated key set to populate dirty keys for clean (#14905)
Don't need to scan the stores again when we already found the key
set of updates per slot. Just insert it earlier.

(cherry picked from commit 65315fa4c2)
2021-01-29 18:02:42 -08:00
Michael Vines
116d67e1e3 Prevent bricked install when ^C is pressed during archive extraction
(cherry picked from commit 7ad9870071)
2021-01-29 18:02:25 -08:00
mergify[bot]
08bda35fd6 Buffer authority must match upgrade authority for deploys and upgrades (bp #14923) (#14935)
* Buffer authority must match upgrade authority for deploys and upgrades (#14923)

(cherry picked from commit 07cef5a557)

# Conflicts:
#	cli/src/program.rs
#	cli/tests/program.rs

* fix conflicts

Co-authored-by: Jack May <jack@solana.com>
2021-01-29 23:04:23 +00:00
mergify[bot]
ba1d0927e6 docs: Fix mangled getConfirmedTransaction parameter list (#14921)
(cherry picked from commit 52326d53be)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-01-29 13:53:53 -07:00
mergify[bot]
555df9f96c cli: Improve reliability of program deploys (#14902) (#14925)
* cli: Improve reliability of program deploys

* chore: fix clippy

(cherry picked from commit 996a27d475)

Co-authored-by: Justin Starry <justin@solana.com>
2021-01-29 13:07:31 -07:00
mergify[bot]
99166a4a59 program-test: Expose bank task to fix fuzzing (#14908) (#14927)
* program-test: Expose bank task to fix fuzzing

* Run cargo fmt and clippy

* Remove unnecessary print in test

* Review feedback

* Transition to AtomicBool

(cherry picked from commit 0ce08274f9)

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-01-29 20:57:56 +01:00
Michael Vines
92534849db Fix cli usage build
(cherry picked from commit 2e54b6acb1)
2021-01-29 11:45:56 -08:00
mergify[bot]
5ba8b4884b Ignore syscalls which are not registered in cached rbpf executable. (#14898) (#14929)
(cherry picked from commit d026da4a1b)

Co-authored-by: Alexander Meißner <AlexanderMeissner@gmx.net>
2021-01-29 11:07:54 -08:00
Trent Nelson
cb878f2ea8 Add feature for pending SPL Token self-transfer fix
(cherry picked from commit 85b5dbead6)
2021-01-29 10:34:04 -07:00
mergify[bot]
b1d5bf30d2 Remove potentially too costly Packets::default() (#14821) (#14915)
* Remove potentially too costly Packets::default()

* Fix test...

* Restore Packets::default()

* Restore Packets::default() more

(cherry picked from commit d6873b82ab)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-01-29 13:52:33 +09:00
Michael Vines
481c60e287 Surface faucet start failures to the user of solana-test-validator
(cherry picked from commit 8993ac0c74)
2021-01-28 16:59:44 -08:00
Eric Williams
86242dc3ba format to list 2021-01-28 16:14:42 -07:00
mergify[bot]
71899deb53 Reorg and cleanup of economics section of docs (#14868) (#14889) 2021-01-28 16:07:31 -07:00
Tyera Eulberg
7e2e0d4a86 Manually camelCase solana program json (#14907) 2021-01-28 13:41:57 -07:00
mergify[bot]
d4cc7c6b66 Only mmap file from snapshot once (#14815) (#14901)
(cherry picked from commit a53b8558cd)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-01-28 11:03:40 -08:00
mergify[bot]
b62349f081 cli now supports a custodian for stake authorize operations (#14860)
Co-authored-by: Michael Vines <mvines@gmail.com>
2021-01-28 18:30:43 +00:00
mergify[bot]
d16638dc90 Add syscall feature activation test (#14890) (#14895)
(cherry picked from commit 63429507b2)

Co-authored-by: Jack May <jack@solana.com>
2021-01-28 09:57:46 -08:00
mergify[bot]
b97fc31fcd nit: message doesn't represent (#14893) (#14897)
(cherry picked from commit 2ca0872a98)

Co-authored-by: Jack May <jack@solana.com>
2021-01-28 09:57:23 -08:00
Michael Vines
4378634970 Bump version to 1.5.6 2021-01-27 10:50:56 -08:00
Trent Nelson
10e12d14e1 install: Add version envvar to info --eval output
(cherry picked from commit dcb6f68287)
2021-01-27 09:05:17 -08:00
mergify[bot]
c5cfbee853 Aggregate purge and shrink metrics (#14763) (#14883)
Co-authored-by: Carl Lin <carl@solana.com>
(cherry picked from commit 72f10f5f29)
2021-01-27 02:56:45 -08:00
mergify[bot]
c276670a94 Snapshots missing slots from accounts cache clean optimization (#14852) (#14878)
Co-authored-by: Carl Lin <carl@solana.com>
2021-01-26 22:20:07 -08:00
Michael Vines
676da0a836 Ensure sanitary transactions
(cherry picked from commit 04ce33a04e)
2021-01-26 17:03:01 -08:00
Michael Vines
0021cf924f solana decode-transaction no longer panics on unsanitary transactions
(cherry picked from commit e9b5d65f40)
2021-01-26 17:03:01 -08:00
Michael Vines
d593ee187c chore: comment blockHeight
(cherry picked from commit 8cd036938e)
2021-01-26 17:01:41 -08:00
Michael Vines
a07bfc2d76 test: account for rent collection to avoid bogus test failure
(cherry picked from commit fba0e933a4)
2021-01-26 17:01:41 -08:00
Michael Vines
f0e9843dd4 fix: add Clock sysvar to AuthorizeWithSeed instruction
(cherry picked from commit fd06c1f8fa)
2021-01-26 17:01:41 -08:00
Michael Vines
a2f643e7c7 Include Clock sysvar in AuthorizeWithSeed instruction
(cherry picked from commit 8359f4f5ff)
2021-01-26 17:01:41 -08:00
Michael Vines
7ebaf1c192 Add StakeInstruction::Merge logging
(cherry picked from commit ff22091a98)
2021-01-26 17:01:33 -08:00
sakridge
6a61e7a01e Enable accounts caching by default (#14854)
Co-authored-by: Carl Lin <carl@solana.com>
(cherry picked from commit 5bf5a5ec41)
2021-01-26 16:56:57 -08:00
Jack May
1c23f135bf Bump rbpf to v0.2.4 (#14867) 2021-01-26 22:49:57 +00:00
mergify[bot]
3c67f71695 Deprecate commitment variants (bp #14797) (#14858)
* Deprecate commitment variants (#14797)

* Deprecate commitment variants

* Add new CommitmentConfig builders

* Add helpers to avoid allowing deprecated variants

* Remove deprecated transaction-status code

* Include new commitment variants in runtime commitment; allow deprecated as long as old variants persist

* Remove deprecated banks code

* Remove deprecated variants in core; allow deprecated in rpc/rpc-subscriptions for now

* Heavier hand with rpc/rpc-subscription commitment

* Remove deprecated variants from local-cluster

* Remove deprecated variants from various tools

* Remove deprecated variants from validator

* Update docs

* Remove deprecated client code

* Add new variants to cli; remove deprecated variants as possible

* Don't send new commitment variants to old clusters

* Retain deprecated method in test_validator_saves_tower

* Fix clippy matches! suggestion for BPF solana-sdk legacy compile test

* Refactor node version check to handle commitment variants and transaction encoding

* Hide deprecated variants from cli help

* Add cli App comments

(cherry picked from commit ffa5c7dcc8)

* Fix 1.5 stake-o-matic

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-01-26 20:49:04 +00:00
mergify[bot]
d380b9cef7 Add more upgradeable tests (#14846) (#14850)
(cherry picked from commit e57b9c3b02)

Co-authored-by: Jack May <jack@solana.com>
2021-01-26 09:42:49 -08:00
Jack May
7415821156 Rotate feature key: use loaded executable accounts (#14838)
(cherry picked from commit 74c83e6854)
2021-01-26 08:53:59 -08:00
Ryo Onodera
4a6c3a9331 Add security best practice sections (#14798)
(cherry picked from commit 60611ae8a0)
2021-01-26 08:53:54 -08:00
Jack May
0cd1cce588 Update find_program_address docs (#14840)
(cherry picked from commit 4a4881d30f)
2021-01-26 08:53:44 -08:00
Michael Vines
f762b4a730 Remove legacy_stake program
(cherry picked from commit 2b50433099)
2021-01-26 08:53:38 -08:00
behzad nouri
08f7f2546e fixes test_filter_current flakiness (#14816)
(cherry picked from commit d1df9da7d3)
2021-01-25 12:44:46 -08:00
mergify[bot]
cb701fbbd9 Reduce ~2 GBs mem by avoiding another overalloc. (#14806) (#14820)
* Reduce few GBs mem by avoiding another overalloc.

* Use x.len() for the last item from chunks()

(cherry picked from commit 015058e0b7)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-01-25 08:08:33 +00:00
mergify[bot]
231ff7d70d removes redundant epoch stakes cache in retransmit (#14781) (#14817)
Following d6d76219b, staked nodes computed from vote accounts are
already cached in runtime::Stakes, so the caching in retransmit_stage is
redundant.

(cherry picked from commit e1021d9f83)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-01-25 01:11:58 +00:00
mergify[bot]
a154414e65 patches crds vote-index assignment bug (bp #14438) (#14741)
* patches crds vote-index assignment bug (#14438)

If tower is full, old votes are evicted from the front of the deque:
https://github.com/solana-labs/solana/blob/2074e407c/programs/vote/src/vote_state/mod.rs#L367-L373
whereas recent votes if expire are evicted from the back:
https://github.com/solana-labs/solana/blob/2074e407c/programs/vote/src/vote_state/mod.rs#L529-L537

As a result, from a single tower_index scalar, we cannot infer which crds-vote
should be overwritten:
https://github.com/solana-labs/solana/blob/2074e407c/core/src/crds_value.rs#L576

In addition there is an off by one bug in the existing code. tower_index is
bounded by MAX_LOCKOUT_HISTORY - 1:
https://github.com/solana-labs/solana/blob/2074e407c/core/src/consensus.rs#L382
So, it is at most 30, whereas MAX_VOTES is 32:
https://github.com/solana-labs/solana/blob/2074e407c/core/src/crds_value.rs#L29
Which means that this branch is never taken:
https://github.com/solana-labs/solana/blob/2074e407c/core/src/crds_value.rs#L590-L593
so crds table alwasys keeps 29 **oldest** votes by wallclock, and then
only overrides the 30st one each time. (i.e a tally of only two most
recent votes).

(cherry picked from commit 8e581601d6)

* removes unnecessary semicolon

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-01-24 21:24:16 +00:00
mergify[bot]
673c679523 Partial clean (#14800) (#14813)
* Revert "Revert "Partial accounts clean (#14652)" (#14777)"

This reverts commit ad2e10e17b.

* Remove squashed uncleaned keys

(cherry picked from commit 0d32a0e0f4)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-01-24 20:52:23 +00:00
mergify[bot]
65a7621b17 broadcasts duplicate shreds through gossip (bp #14699) (#14812)
* broadcasts duplicate shreds through gossip (#14699)

(cherry picked from commit 491b059755)

# Conflicts:
#	core/src/cluster_info.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-01-24 17:45:35 +00:00
mergify[bot]
c9da25836a Upgrade to Rust v1.49.0 (bp #14810) (#14811)
* Upgrade to Rust v1.49.0

(cherry picked from commit cbffab7850)

# Conflicts:
#	core/src/crds_value.rs

* rebase

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-01-24 04:42:09 +00:00
mergify[bot]
b48dd58fda Upgrade sha2 to 0.9.3 (#14746) (#14799)
(cherry picked from commit 191193289f)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-01-23 23:08:33 +00:00
mergify[bot]
40f32fd37d Speed up generate_index (#14792) (#14807)
(cherry picked from commit 424bb797a6)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-01-23 18:50:04 +00:00
mergify[bot]
fef4100f5f Remove unnecesary flushes in previous roots (#14596) (#14803)
Co-authored-by: Carl Lin <carl@solana.com>
(cherry picked from commit c77461e428)

Co-authored-by: carllin <wumu727@gmail.com>
2021-01-23 15:02:32 +00:00
mergify[bot]
68bf58aac0 Parallel cache scan (#14544) (#14804)
Co-authored-by: Carl Lin <carl@solana.com>
(cherry picked from commit 2745b79b74)

Co-authored-by: carllin <wumu727@gmail.com>
2021-01-23 13:42:47 +00:00
mergify[bot]
5677662d61 Improve documentation of sendTransaction (#14770) (#14802)
* Improve documentation of sendTransaction

* Apply suggestions from code review

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

* Word wrap and improve terminology

* Tweak

* Oops

* Apply suggestions from code review

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

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

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-01-23 10:02:29 +00:00
mergify[bot]
6755fd0c96 Make exchange listening-for-deposits language stronger (#14775) (#14801)
* Make exchange listening-for-deposits language stronger

* Update docs/src/integrations/exchange.md

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

* Update from deprecated method

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

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-01-23 07:27:58 +00:00
mergify[bot]
dfbe38b859 Add solana-test-validator --warp-slot argument (bp #14785) (#14796)
* Add convenience function to create a snapshot archive out of any Bank

(cherry picked from commit dd5a2ef05f)

* Add solana-test-validator --warp-slot argument

(cherry picked from commit bf1943e489)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-01-23 06:38:16 +00:00
mergify[bot]
480a35d678 Track account writable deescalation (bp #14626) (#14787)
* Track account writable deescalation (#14626)

(cherry picked from commit 77572a7c53)

# Conflicts:
#	sdk/src/feature_set.rs

* fix conflicts

Co-authored-by: Jack May <jack@solana.com>
2021-01-23 03:33:21 +00:00
sakridge
e6b53c262b Revert "Partial accounts clean (#14652) (#14751)" (#14776)
This reverts commit c89f5e28b7.
2021-01-22 16:17:20 -08:00
mergify[bot]
e127631f8d Add ability to clone accounts from an RPC endpoint (#14784)
(cherry picked from commit cbb9ac19b9)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-01-22 22:47:29 +00:00
mergify[bot]
2d246581ed Add ability to force feature activation without code modification (#14783)
(cherry picked from commit c3548f790c)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-01-22 22:39:56 +00:00
mergify[bot]
952a5b11c1 CLI: Strive for at least one signer (bp #14767) (#14779)
* CLI: Strive for at least one signer

(cherry picked from commit 8f8d593457)

* CLI: Allow missing pubkey in `--verbose` config output

(cherry picked from commit 90e1778cd2)

* CLI: Don't scare the users

(cherry picked from commit e9c98f2416)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-01-22 19:50:50 +00:00
mergify[bot]
c49a8cb67c Rpc: Add custom error for BigTable data not found (#14762) (#14765)
* Expose not-found bigtable error

* Add custom rpc error for bigtable data not found

* Return custom rpc error when bigtable block is not found

* Generalize long-term storage

(cherry picked from commit 71e9958e06)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-01-22 05:56:47 +00:00
mergify[bot]
733a1c85cf Add block_time to getConfirmedSignaturesForAddress2 and getConfirmedTransaction (bp #14572) (#14728)
* Add block_time to getConfirmedSignaturesForAddress2 and getConfirmedTransaction (#14572)

* add block_time to get_confirmed_signatures_for_address2 and protobuf implementation for tx_by_addr

* add tests for convert

* update cargo lock

* run cargo format after rebase

* introduce legacy TransactionByAddrInfo

* move LegacyTransactionByAddrInfo back to storage-bigtable

(cherry picked from commit 1de6d28eaf)

* fix local sanity script

* add missing block_time field

Co-authored-by: Josh <josh.hundley@gmail.com>
2021-01-22 02:02:45 +00:00
mergify[bot]
c8f7719c9e fixes test_filter_current flakiness (bp #14749) (#14761)
* fixes test_filter_current flakiness (#14749)

(cherry picked from commit e4da6761a7)

# Conflicts:
#	core/src/crds_value.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-01-22 01:24:10 +00:00
mergify[bot]
c89f5e28b7 Partial accounts clean (#14652) (#14751)
Clean less keys by tracking the two cases:
* Touched keys per slot in uncleaned_keys derived from
accounts delta hash operation.
* Set of keys with any zero-lamport updates.

Co-authored-by: sakridge <sakridge@gmail.com>
2021-01-22 00:34:49 +00:00
mergify[bot]
38e4c34d18 CLI: Add calculate-rent subcommand (bp #14725) (#14759)
* cli-output: Genericize `writeln_name_value()`

(cherry picked from commit 2820d0a23d)

* CLI: Add `calculate-rent` subcommand

(cherry picked from commit 12410541a4)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-01-22 00:04:07 +00:00
mergify[bot]
afa7343bc2 Add ic_msg()/ic_logger_msg() macros (#14757)
(cherry picked from commit 3c6dbd21d2)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-01-21 23:10:50 +00:00
mergify[bot]
8ea584e01f Update bigtable confirm to use confirmation_status (#14750) (#14754)
(cherry picked from commit ca95302038)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-01-21 22:21:34 +00:00
mergify[bot]
239dc9b0b7 rewrites turbine retransmit peers computation (#14584) (#14742)
(cherry picked from commit b5fd0ed859)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-01-21 14:25:46 +00:00
mergify[bot]
6e6a55b7d6 Add signer/writable de/escalation tests (#14726) (#14739)
(cherry picked from commit aa96ad042b)

Co-authored-by: Jack May <jack@solana.com>
2021-01-21 10:39:08 +00:00
mergify[bot]
815bad8a6c Minor doc clarification (#14733)
(cherry picked from commit 5ac536d0fb)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-01-21 08:13:05 +00:00
mergify[bot]
74f813574f Nonce address doesn't sign AdvanceNonceAccount (#14722)
(cherry picked from commit 447e3de1f2)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-01-21 05:31:55 +00:00
mergify[bot]
07648f43db Make it possible to opt-out jemalloc for heaptrack (#14634) (#14685)
(cherry picked from commit d63b2baf0e)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-01-21 03:32:07 +00:00
mergify[bot]
99f0d29e65 Return confirmation-status (#14709) (#14715)
(cherry picked from commit 0e87572eb0)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-01-21 03:05:53 +00:00
mergify[bot]
87825f3beb Sanitize base58 pubkeys and sigs (bp #14708) (#14712)
* SDK: Sanitize base58 pubkey input

(cherry picked from commit 250b3969d4)

* SDK: Sanitize base58 signature input

(cherry picked from commit 2783aee483)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-01-21 02:39:58 +00:00
mergify[bot]
8e38f90e54 Default to highest finalized block if no slot provided (#14701) (#14704)
(cherry picked from commit c64d4f7693)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-01-20 22:48:32 +00:00
Jack May
d72c90e475 Bump version to v1.5.5 (#14700) 2021-01-20 20:26:16 +00:00
mergify[bot]
459ae81655 Cli: promote commitment to a global arg + config.yml (#14684) (#14698)
* Make commitment a global arg

* Add commitment to solana/cli/config.yml

* Fixup a couple Display/Verbose bugs

(cherry picked from commit a7086a0f83)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-01-20 18:04:25 +00:00
mergify[bot]
a2ce22f11b Bail on small deploy buffers (#14677) (#14682)
(cherry picked from commit a480b63234)

Co-authored-by: Jack May <jack@solana.com>
2021-01-20 03:39:27 +00:00
mergify[bot]
44ad4a1ecd Prevent the invoke and upgrade of programs in the same tx batch (bp #14653) (#14680) 2021-01-19 17:58:45 -08:00
mergify[bot]
fcd8dd75c5 Cli: default to single gossip (#14673) (#14676)
* Init cli RpcClient with chosen commitment; default to single_gossip

* Fill in missing client methods

* Cli tests: make RpcClient commitment specific

* Simply rpc_client calls, using configured commitment

* Check validator vote account with single-gossip commitment

(cherry picked from commit 4964b0fe61)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-01-19 23:58:19 +00:00
mergify[bot]
ca262fdeb9 Configure Bigtable's timeout, enabling by default (#14657) (#14669)
* Configure bigtable's timeout when read-only

* Review comments

* Apply nits (thanks!)

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

* Timeout in the streamed decoding as well

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

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-01-19 15:14:59 +00:00
mergify[bot]
3d6bb95932 Improve docs around bigtable read limit (#14660) (#14662)
(cherry picked from commit 2eb19fa5e5)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-01-19 07:51:44 +00:00
mergify[bot]
e5d36fcfb3 feature gates turbine retransmit peers patch (#14631) (#14659)
(cherry picked from commit c6ae0667e6)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-01-19 05:38:26 +00:00
mergify[bot]
061965e291 Rename RpcNodeUnhealthy error to NodeUnhealthy, generalize getHealth RPC error object for the future (#14656)
(cherry picked from commit 5d9dc609b1)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-01-19 05:24:29 +00:00
mergify[bot]
e56681a2f6 Make Bigtable::get_confirmed_blocks inclusive of requested start_slot and end_slot (#14651) (#14655)
* Fix off-by-one error

* Filter out blocks greater than end slot

(cherry picked from commit cbf8ef7480)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-01-19 03:42:59 +00:00
mergify[bot]
8cf23903ce Fix the occasional stuck RPC request (bp #14628) (#14638)
* WIP fix the occasional stuck RPC request

(cherry picked from commit 5cf9094bb9)

* Clean up and add comment

(cherry picked from commit 8d4ab1bab1)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-01-18 19:57:28 +00:00
mergify[bot]
7ac2aae730 More generic accounts purge functions (#14595) (#14640)
Co-authored-by: Carl Lin <carl@solana.com>
(cherry picked from commit 5f14f45282)

Co-authored-by: carllin <wumu727@gmail.com>
2021-01-18 05:53:40 +00:00
mergify[bot]
6f5b9331bd Add --minimum-validator-identity-balance (#14636)
(cherry picked from commit a12ede8e7d)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-01-18 03:36:58 +00:00
mergify[bot]
a04375e204 Add getSnapshotSlot RPC method (#14632)
(cherry picked from commit 4003f86f04)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-01-16 20:51:33 +00:00
Michael Vines
7b19d26a6e Add getHealth RPC method 2021-01-16 10:51:54 -08:00
Michael Vines
3c3a3f0b50 Improve solana-test-validator output
(cherry picked from commit 1c2ae15b1d)
2021-01-16 10:14:43 -08:00
mergify[bot]
0367b32533 Update-executable flag in pre-accounts (#14622) (#14625)
(cherry picked from commit 66b54b852d)

Co-authored-by: Jack May <jack@solana.com>
2021-01-16 03:05:12 +00:00
mergify[bot]
09392ee562 Support account on tmpfs via net/ scripts (bp #14459) (#14621)
* multinode-demo: Pass --accounts through bootstrap leader wrapper

(cherry picked from commit 327be55acc)

* gce.sh: Factor out default custom memory

(cherry picked from commit ddf1d2dbf5)

* net/: Support accounts on swap-backed tmpfs

(cherry picked from commit ff599ace4d)

* net/gce.sh: Add cusom RAM arg instead of doubling default with tmpfs

(cherry picked from commit 3175cf1deb)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-01-16 00:14:16 +00:00
mergify[bot]
1a848e22ea net/net.sh: Quite pre-emptible instance status check (#14618)
(cherry picked from commit 7b67228bc1)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-01-15 21:19:33 +00:00
mergify[bot]
3d8cadebc0 Use optimistic confirmation in getSignatureStatuses, and various downstream client methods (#14430) (#14611)
* Add optimistically_confirmed field to TransactionStatus

* Update docs

* Convert new field to confirmation_status

* Update docs to confirmationStatus

* Update variants

* Update docs

* Just Confirmed

(cherry picked from commit 9a89689ad3)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-01-15 17:25:04 +00:00
mergify[bot]
47b8d518c5 Use highest-confirmed-root for max check (#14599) (#14604)
(cherry picked from commit 465f991035)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-01-15 15:28:45 +00:00
mergify[bot]
011d2dd41d Fix program-test's CPI support (#14594) (#14597)
* Fix program-test's CPI support

* feedback

(cherry picked from commit 0d29f9e82c)

Co-authored-by: Jack May <jack@solana.com>
2021-01-15 04:44:58 +00:00
mergify[bot]
bdfffd0151 Add load/execute/store timings (#14561) (#14591)
(cherry picked from commit 907f518f6d)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-01-14 23:48:36 +00:00
mergify[bot]
722cebc4c3 docs: Add stake programming documentation (#14529) (#14582)
* Add stake programming documentation

We had some questions about stake programming documentation, and there
wasn't a place that contained information about the stake-o-matic and
other stake development in one place.  This adds a page with that
information.

* Update docs/src/staking/stake-programming.md

Co-authored-by: Eric Williams <eric@solana.com>

* Update docs/src/staking/stake-programming.md

Co-authored-by: Eric Williams <eric@solana.com>

* Update docs/src/staking/stake-programming.md

Co-authored-by: Eric Williams <eric@solana.com>

* Update docs/src/staking/stake-programming.md

Co-authored-by: Eric Williams <eric@solana.com>

* Update docs/src/staking/stake-programming.md

Co-authored-by: Eric Williams <eric@solana.com>

* Apply suggestions from code review

* Remove trailing whitespace

Co-authored-by: Eric Williams <eric@solana.com>
(cherry picked from commit b37dbed479)

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-01-14 16:17:25 +00:00
mergify[bot]
771b98a168 Load executable accounts from invoke context (#14574) (#14575)
(cherry picked from commit 6e8a1ba7de)

Co-authored-by: Jack May <jack@solana.com>
2021-01-14 09:39:26 +00:00
Trent Nelson
1b02ec4f6e Bump version to v1.5.4 2021-01-14 04:40:25 +00:00
mergify[bot]
aae51925c1 patches bug in turbine's neighbors computation (#14565) (#14569)
Removing local node's index early from the set here:
https://github.com/solana-labs/solana/blob/e1b59ded4/core/src/retransmit_stage.rs#L346
distorts the order of nodes depending on which node is computing the
turbine fan-out tree, and results in incorrect neighbors computation.

(cherry picked from commit cfcca1cd3c)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-01-13 23:52:14 +00:00
mergify[bot]
00626fbf4c Add --rpc-threads argument (#14568)
(cherry picked from commit 11daaadc93)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-01-13 22:52:15 +00:00
mergify[bot]
14ffc05fd4 Use leader_forward_count for tx retries too (#14547) (#14564)
(cherry picked from commit e1b59ded4b)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-01-13 19:30:55 +00:00
mergify[bot]
6e5c9a1b1c adds pubkey for behzad@solana.com (#14558) (#14563)
(cherry picked from commit 673cb39975)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-01-13 18:57:10 +00:00
mergify[bot]
1276b92462 Don't stop to find newer cluster-confirmed roots (#14557) (#14560)
* Don't stop to find newer cluster-confirmed roots

* Fix and add new tests

* nits

(cherry picked from commit e95ebcf864)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-01-13 17:05:46 +00:00
Alexander Meißner
89241cedba Bump RBPF version to v0.2.3
(cherry picked from commit 0d26cb6d37)
2021-01-12 09:47:28 -08:00
mergify[bot]
0e3e3a03cc Cache account stores, flush from AccountsBackgroundService (#13140) (#14542)
(cherry picked from commit 6dfad0652f)

Co-authored-by: carllin <wumu727@gmail.com>
2021-01-12 06:12:18 +00:00
Jack May
25fe93e9fb Check native account owner (#14535)
(cherry picked from commit 8ad5931bfc)
2021-01-11 21:29:53 -08:00
mergify[bot]
4440a8d9fa Update timestamp max allowable drift to 50% of PoH (#14531) (#14539)
* Repurpose warp-timestamp feature for general bump

* Change max_allowable_drift to 50%

* Fill in PR#

* Fix rpc test setup

(cherry picked from commit b0e6e29527)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-01-12 02:03:41 +00:00
Michael Vines
b737e562ab Use standard tmp-snapshot- file prefix for the "new_state" archive for better cleanup/consistency 2021-01-11 17:33:10 -08:00
Michael Vines
9cb32b2105 Restore snapshot hard linking 2021-01-11 17:33:03 -08:00
Michael Vines
f46ad1b7b7 Avoid tmp snapshot backlog in SnapshotPackagerService under high load (#14516) 2021-01-11 17:32:58 -08:00
mergify[bot]
b15603b4eb Add rocskdb high priority threads (#14515) (#14536)
Without them, memtable writes can stall on compactions.

(cherry picked from commit d8105bb7d7)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-01-11 23:07:59 +00:00
Michael Vines
c7267799ce Clarify log message, the remote snapshot might not actually be newer 2021-01-11 11:53:55 -08:00
mergify[bot]
ed0a083cd9 Cli: Implement OutputFormat for some missing subcommands (#14518) (#14520)
* Implement OutputFormat for solana leader-schedule

* Implement OutputFormat for solana inflation

(cherry picked from commit e4cf845974)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-01-10 01:20:39 +00:00
mergify[bot]
484bd48b35 Various snapshot-related code clean up (bp #14487) (#14513)
* Create account paths once

(cherry picked from commit fe0ba4a429)

* Replace incorrect symlink_dir usage with symlink_file

(cherry picked from commit f2a7f561a0)

* Reduce TempDir exposure

(cherry picked from commit 9f70f7dc3e)

* Rename AccountsPackage::root to AccountsPackage::slot

(cherry picked from commit 141e6706e6)

* Rename CompressionType to ArchiveFormat

(cherry picked from commit 7be6770808)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-01-09 18:29:09 +00:00
mergify[bot]
ae73cc8d05 Humanize the 'ledger processed...' time (#14511)
(cherry picked from commit 86c81a0ba2)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-01-09 08:14:14 +00:00
mergify[bot]
fc59a08f0e Bail on all CPI errors (#14500) (#14507)
* Bail on all CPI errors

* whitespace

(cherry picked from commit ec48631fc5)

Co-authored-by: Jack May <jack@solana.com>
2021-01-09 04:44:14 +00:00
mergify[bot]
15da7968c5 Add cli command to query upgradeable account authorities (#14491) (#14499)
(cherry picked from commit 638f225dc4)

Co-authored-by: Jack May <jack@solana.com>
2021-01-09 01:13:20 +00:00
mergify[bot]
b58a6e2b6e Report correct program id (#14486) (#14498)
(cherry picked from commit 9d53eca6e3)

Co-authored-by: Jack May <jack@solana.com>
2021-01-09 01:00:42 +00:00
Michael Vines
ec15ea079f Bump version to 1.5.3 2021-01-08 16:19:27 -08:00
mergify[bot]
4b5a05bf38 limits number of crds values associated with a pubkey (bp #14467) (#14490)
* limits number of crds values associated with a pubkey (#14467)

(cherry picked from commit 766195dded)

* updates smallvec

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-01-08 21:52:40 +00:00
mergify[bot]
7dd7141307 Suppress cargo audit failure for difference crate (bp #14488) (#14493)
* Suppress cargo audit failure for `difference` crate, there's no newer crate to upgrade to yet

(cherry picked from commit 3eaa826ad9)

* Bump smallvec version

(cherry picked from commit 21a0a83543)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-01-08 21:52:28 +00:00
mergify[bot]
e5175c843d Add buffer authority to upgradeable loader (#14482) (#14485)
(cherry picked from commit 58487c6360)

Co-authored-by: Jack May <jack@solana.com>
2021-01-08 18:54:11 +00:00
mergify[bot]
d5ff64b0d7 docs: Validator tuning improvements (bp #14478) (#14480)
* docs: wrap lines

(cherry picked from commit 140642ea21)

* docs: Prefer `dd` to `fallocate` when creating swap file

(cherry picked from commit c035f2a745)

* docs: Add RUST_LOG explainer

(cherry picked from commit 30038a8849)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-01-07 19:41:45 +00:00
mergify[bot]
0fbdc7e152 Enable program upgrades via CPI (#14449) (#14469)
(cherry picked from commit 5eacc5d08d)

Co-authored-by: Jack May <jack@solana.com>
2021-01-06 23:45:10 +00:00
Tyera Eulberg
49aca9ecd8 Add fixed tick rate adjustment (#14447) (#14464)
Co-authored-by: sakridge <sakridge@gmail.com>
2021-01-06 21:44:06 +00:00
mergify[bot]
fcc147b4f2 Gate cpi program account passing (#14443) (#14446)
(cherry picked from commit a8b5a32b50)

Co-authored-by: Jack May <jack@solana.com>
2021-01-06 19:20:49 +00:00
mergify[bot]
c455d1b1c5 Enable program-id account index for supply calculations (#14444) (#14456)
* Enable program-id account index for supply calculations

* Fixup comments

(cherry picked from commit ce1766d798)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-01-06 04:04:44 +00:00
mergify[bot]
e9b29fc697 Bump serum-dex pegged commit (#14448) (#14454)
(cherry picked from commit d2b0fd973f)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-01-05 19:17:03 -07:00
Ryo Onodera
fdea6fad26 Save 7G mem on mainnet fixing AccIndex overalloc. (#14435)
(cherry picked from commit c9df6134fa)
2021-01-05 17:55:44 -08:00
mergify[bot]
a4bc31341a Lower recycle store count (#14429) (#14442)
Too many stores can cause swap usage which
is detrimental to account store times.

(cherry picked from commit 53d65009a0)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-01-05 21:39:31 +00:00
mergify[bot]
4af797c0a2 Introduce rpc url monikers for cli (#14409) (#14433)
* Introduce rpc url monikers for cli

* Use https:// and support initials as well

(cherry picked from commit 54a5876c48)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-01-05 12:16:11 +00:00
mergify[bot]
a1e06df4a8 Add validator --account-index docs (#14418) (#14428)
(cherry picked from commit efd9b769fc)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-01-05 03:06:15 +00:00
mergify[bot]
1f2480fd9f Fix pre-merge old name in the docs (#14425) (#14427)
(cherry picked from commit 974eb6e1ef)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-01-05 02:55:02 +00:00
mergify[bot]
8587bd0d69 Improve solana catchup (#14313) (#14424)
* Improve solana catchup

* Overidable port, retry, args error clean up

* print cleanup

* Reduce diff

* Tweak warns a bit

(cherry picked from commit aa4da339ff)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-01-05 02:34:53 +00:00
mergify[bot]
0063a58e95 Upgradeable programs needs program account's address as program id (#14417) (#14420)
(cherry picked from commit 0619805806)

Co-authored-by: Jack May <jack@solana.com>
2021-01-04 23:00:36 +00:00
mergify[bot]
9aeb3bc5d6 docs: Use "msg!" instead of "info!" (#14411) (#14416)
* docs: Use "msg!" instead of "info!"

* Update docs/src/developing/deployed-programs/developing-rust.md

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

* Fix typo / format

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

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-01-04 20:02:09 +00:00
Michael Vines
97665b977e Bump version to v1.5.2 2021-01-04 06:44:52 +00:00
Michael Vines
c45ed29cf4 Use max commitment when fetching epoch info for block production
(cherry picked from commit 2724f37d0e)
2021-01-03 21:05:13 -08:00
mergify[bot]
635afbabff snapshot_utils: Don't bother restoring snapshots, they're never used (bp #14392) (#14396)
* Remove dead code

(cherry picked from commit b6dcdb90e8)

* Don't bother restoring snapshots, they're never used

(cherry picked from commit db6ee289c9)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-01-03 05:20:26 +00:00
mergify[bot]
98afdad1dd Tune rewards output (#14395)
(cherry picked from commit 560ed90168)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-01-03 02:39:35 +00:00
mergify[bot]
c085b94b43 docs: Update tmpfs partition guidance to include swap (bp #14387) (#14397)
* Update tmpfs partition guidance to include swap

(cherry picked from commit 68a84cf581)

* Update docs/src/running-validator/validator-start.md

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

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-01-03 01:45:07 +00:00
Michael Vines
a53946c485 Use singleGossip for program deployment
(cherry picked from commit c63e14dd0e)
2021-01-02 09:21:36 -08:00
mergify[bot]
f6de92c346 Add secondary indexes (#14212) (#14382)
(cherry picked from commit 5affd8aa72)

Co-authored-by: carllin <wumu727@gmail.com>
2021-01-01 07:42:47 +00:00
mergify[bot]
46f9822d62 Only initialize BigTable upload service when requested (#14380)
(cherry picked from commit 4a3d217839)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-01-01 03:06:34 +00:00
mergify[bot]
6dad84d228 Add --ignore-http-bad-gateway flag (#14377)
(cherry picked from commit 6c167615ad)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-12-31 22:00:29 +00:00
mergify[bot]
3582607aa0 solana-test-validator: bind RPC and faucet to 0.0.0.0 (bp #14369) (#14370)
* Minor help improvements

(cherry picked from commit 04bf5ce830)

* Bind RPC and faucet to 0.0.0.0

(cherry picked from commit 0b23abd479)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-12-31 09:10:07 +00:00
Michael Vines
f051077350 Require tokio 0.3.5 2020-12-30 22:25:23 -08:00
Michael Vines
ffd6f3e6bf Revert "Upgrade in-tree tokio 0.2 usage to tokio 0.3 (#14326)"
This reverts commit 6c5be574c8.
2020-12-30 22:25:23 -08:00
mergify[bot]
c6b2eb07ee Gate CPI authorized programs (#14361) (#14365)
(cherry picked from commit 2d8dacb72b)

Co-authored-by: Jack May <jack@solana.com>
2020-12-31 03:29:46 +00:00
mergify[bot]
7a3e1f9826 Remove assert (#14356) (#14360)
(cherry picked from commit 1c5427ff17)

Co-authored-by: Jack May <jack@solana.com>
2020-12-30 22:39:55 +00:00
mergify[bot]
8a690b6cf7 nit: clarify loader id (#14355) (#14358)
(cherry picked from commit 6c6095abe7)

Co-authored-by: Jack May <jack@solana.com>
2020-12-30 21:25:41 +00:00
mergify[bot]
8688efa89b Speed up UDP reachable port checks (#14351)
(cherry picked from commit 71b88da48e)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-12-30 19:00:28 +00:00
mergify[bot]
3b047e5b99 Port ip-echo-server to tokio 0.3 (bp #14345) (#14350)
* Port ip-echo-server to tokio 0.3

(cherry picked from commit fb6c660cfd)

# Conflicts:
#	net-utils/Cargo.toml

* Update Cargo.toml

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-12-30 18:55:24 +00:00
mergify[bot]
3cddc731b2 Add --test arg to cargo-test-bpf (#14342) (#14344)
(cherry picked from commit 3d0cd2cdb0)

Co-authored-by: Justin Starry <justin@solana.com>
2020-12-30 07:55:38 +00:00
mergify[bot]
1d29a583c6 Rewrite faucet with tokio v0.3 (bp #14336) (#14343)
* Rewrite faucet with tokio v0.3 (#14336)

* Rewrite faucet for contemporary tokio

* Move away from framed decoder

(cherry picked from commit d63dd95806)

# Conflicts:
#	faucet/Cargo.toml

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2020-12-30 05:09:00 +00:00
mergify[bot]
b5335edb35 Add experimental knob for tuning PoH pinned CPU core (bp #14330) (#14341)
* core: Update stale error message

(cherry picked from commit 82f61c0c4a)

* validator: Add experimental flag to select PoH pinned core

(cherry picked from commit fe667db910)

Co-authored-by: Trent Nelson <trent@solana.com>
2020-12-30 03:33:39 +00:00
mergify[bot]
abee1e83eb Add poh speed check and tick speed calibration (#14292) (#14328)
(cherry picked from commit 2074e407cd)

Co-authored-by: sakridge <sakridge@gmail.com>
2020-12-29 19:40:49 +00:00
mergify[bot]
6c5be574c8 Upgrade in-tree tokio 0.2 usage to tokio 0.3 (#14326)
(cherry picked from commit 444ed768dc)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-12-29 19:03:18 +00:00
mergify[bot]
c1f993d2fc Retry durable-nonce transactions (#14308) (#14325)
* Retry durable-nonce transactions

* Add metric to track durable-nonce txs in queue

* Populate send-tx-service initial addresses with tpu_address if empty (primarily for testing)

* Reinstate last_valid_slot check for durable-nonce txs; use arbitrary future slot

(cherry picked from commit 3f10fb993b)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-12-29 18:03:04 +00:00
mergify[bot]
e2ddb2f0ea Limit CPI instruction size (#14317) (#14321)
(cherry picked from commit 5524938a50)

Co-authored-by: Jack May <jack@solana.com>
2020-12-29 02:38:22 +00:00
mergify[bot]
f3faba5ca9 Remove Testnet-specific old code (#14305) (#14315)
(cherry picked from commit 7893e2e307)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-12-28 22:18:33 +00:00
mergify[bot]
3a6fd91739 Log error from AppendVec removal & a panic clean (#14302) (#14310)
(cherry picked from commit addffd7694)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-12-28 22:08:22 +00:00
mergify[bot]
2d2b3d8287 CLI: Support retrieving past leader schedules (bp #14304) (#14312)
* clap-utils: Add epoch validator

(cherry picked from commit a709850ee4)

* CLI: Support displaying past leader schedules

(cherry picked from commit bd761e2a52)

Co-authored-by: Trent Nelson <trent@solana.com>
2020-12-28 21:41:55 +00:00
mergify[bot]
6e47b88399 run.sh: add env knob for solana-validor (#14303) (#14307)
(cherry picked from commit 4af33674a7)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-12-28 20:48:03 +00:00
Michael Vines
941e56c6c7 Avoid creating "..tmp" files 2020-12-28 08:58:41 -08:00
Michael Vines
d1adc2a446 Persist gossip contact info
(cherry picked from commit 9ddd6f08e8)
2020-12-27 22:09:00 -08:00
Michael Vines
02da7dfedf Bump version to v1.5.1 2020-12-27 21:57:43 -08:00
mergify[bot]
eb0fd3625a Fix subtraction overflow in metrics (#14290) (#14296)
(cherry picked from commit c693ffaa08)

Co-authored-by: sakridge <sakridge@gmail.com>
2020-12-28 02:34:58 +00:00
mergify[bot]
b87e606626 Fix download speed (#14291) (#14295)
(cherry picked from commit 7b49c85aa7)

Co-authored-by: sakridge <sakridge@gmail.com>
2020-12-28 02:21:40 +00:00
mergify[bot]
1c91376f78 obtains staked-nodes from the root-bank (#14257) (#14293)
... as opposed to the working bank

(cherry picked from commit 49019c6613)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2020-12-27 14:49:29 +00:00
mergify[bot]
10067ad07b indexes votes in crds table (#14272) (#14294)
(cherry picked from commit 2fd38d9912)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2020-12-27 14:49:23 +00:00
Michael Vines
eb76289107 Fix windows build 2020-12-24 17:49:41 -08:00
Michael Vines
8926736e1c Remove stray dbg 2020-12-24 10:45:34 -08:00
mergify[bot]
bf4c169703 Prevent bpf loader impersonators (#14278) (#14279)
(cherry picked from commit ee0a80a092)

Co-authored-by: Jack May <jack@solana.com>
2020-12-24 04:24:30 +00:00
mergify[bot]
0020e43476 Don't use caller passed executable account (#14276) (#14277)
(cherry picked from commit b1d702a618)

Co-authored-by: Jack May <jack@solana.com>
2020-12-23 23:52:04 +00:00
mergify[bot]
a9a2c76221 Limit CPI from calling loader or native programs (#14252) (#14275)
(cherry picked from commit 0b479ab180)

Co-authored-by: Jack May <jack@solana.com>
2020-12-23 20:01:56 +00:00
mergify[bot]
4754b4e871 Save cloning program account data (#14251) (#14274)
(cherry picked from commit 5945305b1d)

Co-authored-by: Jack May <jack@solana.com>
2020-12-23 19:35:09 +00:00
mergify[bot]
52ffb9a64a Add accounts shrink paths (bp #14238) (#14270)
* Add shrink paths (#14238)


(cherry picked from commit baa9602411)

* Ignore long/hanging test (#14261)

Co-authored-by: sakridge <sakridge@gmail.com>
Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-12-23 08:03:33 +00:00
Trent Nelson
bd0b1503c6 Deinitialize stake data upon zero balance 2020-12-23 06:17:59 +00:00
Trent Nelson
10e7fa40ac Deinitialize vote data upon zero balance 2020-12-23 06:17:59 +00:00
Trent Nelson
198ed407b7 vote: Add helper for creating current-versioned states 2020-12-23 06:17:59 +00:00
Trent Nelson
d96af2dd23 Deinitialize nonce data upon zero balance 2020-12-23 06:17:59 +00:00
mergify[bot]
192cca8f98 validator: Multiple --entrypoint support (bp #14256) (#14264)
* Update entrypoint contact info even when shred version adoption is not requested

(cherry picked from commit 3373082ffa)

* Multiple entrypoint support

(cherry picked from commit ace360ade2)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-12-23 04:15:44 +00:00
Michael Vines
ee716e1c55 Add log message for when a local snapshot is too old
(cherry picked from commit 65dcb3dc81)
2020-12-22 19:58:29 -08:00
mergify[bot]
6dd3c7c2dd removes &Arc<Self> receivers (#14234) (#14262)
(cherry picked from commit a14cfd660a)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2020-12-23 02:11:08 +00:00
mergify[bot]
582b4c9edf Upgradeable programs called same as non-upgradeable (#14239) (#14254)
* Upgradeable programs called same as non-upgradeable

* nudge

(cherry picked from commit ab205b682a)

Co-authored-by: Jack May <jack@solana.com>
2020-12-22 21:17:18 +00:00
mergify[bot]
f15add2a74 Feature-gate stake-program-v3 (#14232) (#14250)
* Remove deprecated legacy stake program

* Add legacy stake program

* Strip out duplicative legacy code

* Feature-deploy stake-program-v3

* Add ownership check in stake processor

(cherry picked from commit 7042f11791)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-12-22 19:42:30 +00:00
mergify[bot]
74d48910e2 Rework upgradeable loader cli (#14209) (#14236)
(cherry picked from commit 3316e7166c)

Co-authored-by: Jack May <jack@solana.com>
2020-12-21 22:26:11 +00:00
mergify[bot]
c53e8ee3ad improves performance in replay-stage (#14217) (#14233)
bank::vote_accounts returns a hash-map which is slow to iterate, but all uses
only require an iterator:
https://github.com/solana-labs/solana/blob/b3dc98856/runtime/src/bank.rs#L4300-L4306
Similarly, calculate_stake_weighted_timestamp takes a hash-map whereas it only
requires an iterator:
https://github.com/solana-labs/solana/blob/b3dc98856/sdk/src/stake_weighted_timestamp.rs#L21-L28

(cherry picked from commit 7b08cb1f0d)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2020-12-21 21:23:35 +00:00
Michael Vines
c5e5fedc47 Allow multiple --accounts arguments
(cherry picked from commit 8082a2454c)
2020-12-21 11:43:04 -08:00
Tyera Eulberg
b9929dcd67 Warp-timestamp pr# 2020-12-21 10:53:43 -07:00
sakridge
554a158443 Fix test_max_hashes (#14189)
(cherry picked from commit a5db6399ad)
2020-12-21 09:05:26 -08:00
behzad nouri
b7fa4b7ee1 caches staked nodes computed from vote-accounts (#13929)
(cherry picked from commit d6d76219b6)
2020-12-21 09:05:17 -08:00
behzad nouri
fd44cee8cc limits number of crds values returned when responding to pull requests (#13739)
Crds values buffered when responding to pull-requests can be very large taking a lot of memory.
Added a limit for number of buffered crds values based on outbound data budget.

(cherry picked from commit 691031fefd)
2020-12-21 09:04:50 -08:00
mergify[bot]
c6a362cce2 Do not delete ALL other snapshots before downloading a new snapshot (#14227)
(cherry picked from commit 93ae177503)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-12-21 10:27:25 +00:00
mergify[bot]
252180c244 Restore Content-Length header for streaming snapshot download (#14222)
(cherry picked from commit 57b03c5bc1)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-12-21 08:41:02 +00:00
mergify[bot]
e02b4e698e Fix timestamp handling on ledger warp (#14210) (#14218)
* Reset timestamp for slot and epoch-start on warp

* Fix genesis timestamp metric source

* Remove check that timestamp > unix_timestamp_from_genesis

Default to previous timestamp, not genesis timestamp

* Move timestamp metrics to report even on warp

* Initialize slot 0 timestamps correctly

* Add feature gate to warp testnet timestamp

* Review suggestion: simplify warp-timestamp slot check

(cherry picked from commit e15f95a36f)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-12-20 22:52:23 +00:00
mergify[bot]
4811afe8eb Stream RPC snapshot downloads (bp #14213) (#14215)
* Stream RPC snapshot downloads

(cherry picked from commit b3dc988564)

# Conflicts:
#	core/Cargo.toml

* Update Cargo.toml

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-12-20 01:28:41 +00:00
Michael Vines
bc4568b10f Update Cargo.toml 2020-12-18 20:16:48 -08:00
Michael Vines
d59c131e90 Create a random -keypair.json file alongside the program deploy artifact for easy upgrades
(cherry picked from commit 636a455790)
2020-12-18 20:16:48 -08:00
Michael Vines
825027f9f7 Use AsRef
(cherry picked from commit 9993d2c623)
2020-12-18 20:16:48 -08:00
mergify[bot]
9b8f0bee99 adds crds-value for broadcasting duplicate shreds through gossip (bp #14133) (#14203)
* adds crds-value for broadcasting duplicate shreds through gossip (#14133)

In gossip, the header overhead we get from:
https://github.com/solana-labs/solana/blob/de9ac43eb/core/src/cluster_info.rs#L434-L435
https://github.com/solana-labs/solana/blob/de9ac43eb/core/src/crds_value.rs#L31-L36
https://github.com/solana-labs/solana/blob/de9ac43eb/core/src/crds_value.rs#L73
already exceeds SIZE_OF_NONCE in shreds. We also need aditional
meta-data (wallclock, source pubkey, ...). Which means that given the
SHRED_PAYLOAD_SIZE, we cannot fit all these in PACKET_DATA_SIZE:
https://github.com/solana-labs/solana/blob/de9ac43eb/ledger/src/shred.rs#L80

On top of that, we need 2 shred payloads as the proof of duplicate. So
each DuplicateShred crds value includes only a chunk of the payload,
along with the meta-data to reconstruct the full payload from the chunks
on the receiving end.

(cherry picked from commit 6a3797e164)

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

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2020-12-18 22:54:50 +00:00
mergify[bot]
fc13c1d654 getBlockTime RPC method now falls back to BigTable in all cases (#14207)
(cherry picked from commit 0090106f60)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-12-18 22:23:35 +00:00
mergify[bot]
a57758e9c9 Add CPI support for upgradeable loader (bp #14193) (#14199) 2020-12-18 11:23:00 -08:00
Michael Vines
564590462a Add transactionCount field to GetEpochInfo
(cherry picked from commit efc091e28a)
2020-12-18 10:09:30 -08:00
Michael Vines
269f6af97e fix: add transactionCount field to GetEpochInfo
(cherry picked from commit 01fe835e73)
2020-12-18 10:09:30 -08:00
mergify[bot]
57b8a59632 Reject invalid --expected-shred-version (#14183) (#14202)
* Reject invalid --expected-shred-version

* less code

(cherry picked from commit 3c9b853268)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-12-18 19:19:57 +09:00
Trent Nelson
4289f52d2b net/gce.sh: Upgrade to Ubuntu 20.04
(cherry picked from commit 3322b83183)
2020-12-17 18:17:01 -07:00
Trent Nelson
573f68620b net/gce.sh: Switch to SSD boot disks
(cherry picked from commit a0507505f4)
2020-12-17 18:17:01 -07:00
Trent Nelson
4bfe64688b net/gce.sh: Bump machine type to 24-core, 64GB RAM
(cherry picked from commit ffe0532ded)
2020-12-17 18:17:01 -07:00
mergify[bot]
50034848a5 Improved Transaction Forwarding (#13944) (#14195)
* Forwarding

* Dedupe leaders

* Use consistent commitment for last_valid_slot in rpc send_transaction

* Plumb rpc send_transaction options into solana-validator

* Extend num slots banking-stage holds forwarded txs

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

Co-authored-by: sakridge <sakridge@gmail.com>
2020-12-17 18:14:06 -07:00
Michael Vines
981294cbc6 Don't require increased open file limit at ledger creation
Follow-up to 0b92720fdb, `create_new_ledger()` does not require a higher fd limit
2020-12-17 08:49:23 -08:00
mergify[bot]
ff728e5e56 Fix program account rent exemption (#14176) (#14180)
(cherry picked from commit 593ad80954)

Co-authored-by: Jack May <jack@solana.com>
2020-12-17 03:46:43 -08:00
Michael Vines
9aaf41bef2 Don't require increased open file limit in solana-test-validator
Travis CI in particular does not allow the open file limit to be
increased.

(cherry picked from commit 0b92720fdb)
2020-12-16 22:59:56 -08:00
Michael Vines
271eec656c Use an ephemeral mint address if the client keypair is not available
Typically this can occur in a CI environment

(cherry picked from commit 8d700c3b94)
2020-12-16 22:59:56 -08:00
Trent Nelson
13d071607f Revert "Ignore RUSTSEC-2020-0077 until next 1.4 release"
This reverts commit 1792100e2b.
2020-12-17 01:54:26 +00:00
Trent Nelson
ffe35d9a10 Bump SPL crates 2020-12-17 01:54:26 +00:00
mergify[bot]
bb2fb07b39 Add blockstore skipped api (#14145) (#14167)
* Add blockstore api to determine if a slot was skipped

* Return custom rpc error if slot is skipped

(cherry picked from commit ac0d32bc7e)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-12-16 22:26:54 +00:00
mergify[bot]
85fc51dc61 fix formatting error in docs (#14163)
(cherry picked from commit 41a93ced23)

Co-authored-by: Jeff Washington (jwash) <wash678@gmail.com>
2020-12-16 18:51:24 +00:00
mergify[bot]
0276b6c4c2 Correctly show reward percent changes (#14161)
(cherry picked from commit bebfa6e93c)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-12-16 18:15:36 +00:00
mergify[bot]
c481e4fe7f Partial shred deserialize cleanup and shred type differentiation (#14094) (#14139)
* Partial shred deserialize cleanup and shred type differentiation in retransmit

* consolidate packet hashing logic

(cherry picked from commit d4a174fb7c)

Co-authored-by: sakridge <sakridge@gmail.com>
2020-12-16 08:57:21 -08:00
mergify[bot]
76a3b3ad11 Remove lock files from programs/bpf/rust (#14148) (#14158)
(cherry picked from commit 49c3f14016)

Co-authored-by: Jack May <jack@solana.com>
2020-12-16 11:56:48 +00:00
mergify[bot]
356c663e88 check for resize access violations (#14142) (#14152)
(cherry picked from commit 025f886e10)

Co-authored-by: Jack May <jack@solana.com>
2020-12-16 10:28:27 +00:00
mergify[bot]
015bbc1e12 Fix up upgradeable bpf loader activation (#14149)
(cherry picked from commit 501fd83afd)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-12-16 07:54:44 +00:00
mergify[bot]
454a9f3175 Switch solana deploy commitment default from "max" to "singleGossip" (#14146)
(cherry picked from commit db4ac17259)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-12-16 04:46:45 +00:00
mergify[bot]
485b3d64a1 Add Program loader/environment instruction errors (#14120) (#14143)
(cherry picked from commit d513b0c4ca)

Co-authored-by: Jack May <jack@solana.com>
2020-12-16 03:50:04 +00:00
Michael Vines
5d170d83c0 Remove stray println 2020-12-15 16:44:56 -08:00
mergify[bot]
f54d8ea3ab solana-test-validator usability improvements (bp #14129) (#14136)
* Clean up Cargo.toml

(cherry picked from commit d2af09a647)

* Prevent multiple test-validators from using the same ledger directory

(cherry picked from commit f3272db7f7)

* Add --reset flag to allow for easy ledger reset

(cherry picked from commit 00c46c528e)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-12-15 23:21:21 +00:00
mergify[bot]
ef9f54b3d4 Fix race between setting tick height and calculating accounts hash (#14101) (#14132)
Co-authored-by: Carl Lin <carl@solana.com>
(cherry picked from commit 75e9e321de)

Co-authored-by: carllin <wumu727@gmail.com>
2020-12-15 22:05:44 +00:00
mergify[bot]
8d0b102b44 Cleanup ledger builtins (#14083) (#14130)
(cherry picked from commit 582418de5e)

Co-authored-by: Jack May <jack@solana.com>
2020-12-15 21:45:44 +00:00
790 changed files with 35609 additions and 52459 deletions

View File

@@ -50,6 +50,14 @@ pull_request_rules:
label:
add:
- automerge
- name: v1.3 backport
conditions:
- label=v1.3
actions:
backport:
ignore_conflicts: true
branches:
- v1.3
- name: v1.4 backport
conditions:
- label=v1.4
@@ -74,11 +82,3 @@ pull_request_rules:
ignore_conflicts: true
branches:
- v1.6
- name: v1.7 backport
conditions:
- label=v1.7
actions:
backport:
ignore_conflicts: true
branches:
- v1.7

1596
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,5 @@
[workspace]
members = [
"accounts-cluster-bench",
"bench-exchange",
"bench-streamer",
"bench-tps",

View File

@@ -107,41 +107,6 @@ send us that patch!
# Disclaimer
All claims, content, designs, algorithms, estimates, roadmaps,
specifications, and performance measurements described in this project
are done with the Solana Foundation's ("SF") best efforts. It is up to
the reader to check and validate their accuracy and truthfulness.
Furthermore nothing in this project constitutes a solicitation for
investment.
All claims, content, designs, algorithms, estimates, roadmaps, specifications, and performance measurements described in this project are done with the author's best effort. It is up to the reader to check and validate their accuracy and truthfulness. Furthermore nothing in this project constitutes a solicitation for investment.
Any content produced by SF or developer resources that SF provides, are
for educational and inspiration purposes only. SF does not encourage,
induce or sanction the deployment, integration or use of any such
applications (including the code comprising the Solana blockchain
protocol) in violation of applicable laws or regulations and hereby
prohibits any such deployment, integration or use. This includes use of
any such applications by the reader (a) in violation of export control
or sanctions laws of the United States or any other applicable
jurisdiction, (b) if the reader is located in or ordinarily resident in
a country or territory subject to comprehensive sanctions administered
by the U.S. Office of Foreign Assets Control (OFAC), or (c) if the
reader is or is working on behalf of a Specially Designated National
(SDN) or a person subject to similar blocking or denied party
prohibitions.
The reader should be aware that U.S. export control and sanctions laws
prohibit U.S. persons (and other persons that are subject to such laws)
from transacting with persons in certain countries and territories or
that are on the SDN list. As a project based primarily on open-source
software, it is possible that such sanctioned persons may nevertheless
bypass prohibitions, obtain the code comprising the Solana blockchain
protocol (or other project code or applications) and deploy, integrate,
or otherwise use it. Accordingly, there is a risk to individuals that
other persons using the Solana blockchain protocol may be sanctioned
persons and that transactions with such persons would be a violation of
U.S. export controls and sanctions law. This risk applies to
individuals, organizations, and other ecosystem participants that
deploy, integrate, or use the Solana blockchain protocol code directly
(e.g., as a node operator), and individuals that transact on the Solana
blockchain through light clients, third party interfaces, and/or wallet
software.
Any content produced by Solana, or developer resources that Solana provides, are for educational and inspiration purposes only. Solana does not encourage, induce or sanction the deployment of any such applications in violation of applicable laws or regulations.

View File

@@ -1,155 +0,0 @@
# Security Policy
1. [Reporting security problems](#reporting)
4. [Security Bug Bounties](#bounty)
2. [Incident Response Process](#process)
<a name="reporting"></a>
## Reporting security problems to Solana
**DO NOT CREATE AN ISSUE** to report a security problem. Instead, please send an
email to security@solana.com and provide your github username so we can add you
to a new draft security advisory for further discussion.
Expect a response as fast as possible, within one business day at the latest.
<a name="bounty"></a>
## Security Bug Bounties
We offer bounties for critical security issues. Please see below for more details.
Loss of Funds:
$500,000 USD in locked SOL tokens (locked for 12 months)
* Theft of funds without users signature from any account
* Theft of funds without users interaction in system, token, stake, vote programs
* Theft of funds that requires users signature - creating a vote program that drains the delegated stakes.
Consensus/Safety Violations:
$250,000 USD in locked SOL tokens (locked for 12 months)
* Consensus safety violation
* Tricking a validator to accept an optimistic confirmation or rooted slot without a double vote, etc..
Other Attacks:
$100,000 USD in locked SOL tokens (locked for 12 months)
* Protocol liveness attacks,
* Eclipse attacks,
* Remote attacks that partition the network,
DoS Attacks:
$25,000 USD in locked SOL tokens (locked for 12 months)
* Remote resource exaustion via Non-RPC protocols
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 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.
Notes:
* All locked tokens can be staked during the lockup period
<a name="process"></a>
## Incident Response Process
In case an incident is discovered or reported, the following process will be
followed to contain, respond and remediate:
### 1. Establish a new draft security advisory
In response to an email to security@solana.com, a member of the `solana-labs/admins` group will
1. Create a new draft security advisory for the incident at https://github.com/solana-labs/solana/security/advisories
1. Add the reporter's github user and the `solana-labs/security-incident-response` group to the draft security advisory
1. Create a private fork of the repository (grey button towards the bottom of the page)
1. Respond to the reporter by email, sharing a link to the draft security advisory
### 2. Triage
Within the draft security advisory, discuss and determine the severity of the
issue. If necessary, members of the `solana-labs/security-incident-response`
group may add other github users to the advisory to assist.
If it is determined that this not a critical network issue then the advisory
should be closed and if more follow-up is required a normal Solana public github
issue should be created.
### 3. Prepare Fixes
For the affected branches, typically all three (edge, beta and stable), prepare
a fix for the issue and push them to the corresponding branch in the private
repository associated with the draft security advisory.
There is no CI available in the private repository so you must build from source
and manually verify fixes.
Code review from the reporter is ideal, as well as from multiple members of the
core development team.
### 4. Notify Security Group Validators
Once an ETA is available for the fix, a member of the
`solana-labs/security-incident-response` group should notify the validators so
they can prepare for an update using the "Solana Red Alert" notification system.
The teams are all over the world and it's critical to provide actionable
information at the right time. Don't be the person that wakes everybody up at
2am when a fix won't be available for hours.
### 5. Ship the patch
Once the fix is accepted, a member of the
`solana-labs/security-incident-response` group should prepare a single patch
file for each affected branch. The commit title for the patch should only
contain the advisory id, and not disclose any further details about the
incident.
Copy the patches to https://release.solana.com/ under a subdirectory named after
the advisory id (example:
https://release.solana.com/GHSA-hx59-f5g4-jghh/v1.4.patch). Contact a member of
the `solana-labs/admins` group if you require access to release.solana.com
Using the "Solana Red Alert" channel:
1. Notify validators that there's an issue and a patch will be provided in X minutes
2. If X minutes expires and there's no patch, notify of the delay and provide a
new ETA
3. Provide links to patches of https://release.solana.com/ for each affected branch
Validators can be expected to build the patch from source against the latest
release for the affected branch.
Since the software version will not change after the patch is applied, request
that each validator notify in the existing channel once they've updated. Manually
monitor the roll out until a sufficient amount of stake has updated - typically
at least 33.3% or 66.6% depending on the issue.
### 6. Public Disclosure and Release
Once the fix has been deployed to the security group validators, the patches from the security
advisory may be merged into the main source repository. A new official release
for each affected branch should be shipped and all validators requested to
upgrade as quickly as possible.
### 7. Security Advisory Bounty Accounting and Cleanup
If this issue is eligible for a bounty, prefix the title of the security
advisory with one of the following, depending on the severity:
* `[Bounty Category: Critical: Loss of Funds]`
* `[Bounty Category: Critical: Loss of Availability]`
* `[Bounty Category: Critical: DoS]`
* `[Bounty Category: Critical: Other]`
* `[Bounty Category: Non-critical]`
* `[Bounty Category: RPC]`
Confirm with the reporter that they agree with the severity assessment, and
discuss as required to reach a conclusion.
We currently do not use the Github workflow to publish security advisories.
Once the issue and fix have been disclosed, and a bounty category is assessed if
appropriate, the GitHub security advisory is no longer needed and can be closed.
Bounties are currently awarded once a quarter (TODO: link to this process, or
inline the workflow)

View File

@@ -1,11 +1,10 @@
[package]
name = "solana-account-decoder"
version = "1.6.3"
version = "1.5.7"
description = "Solana account decoder"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-account-decoder"
license = "Apache-2.0"
edition = "2018"
@@ -16,14 +15,14 @@ bs58 = "0.3.1"
bv = "0.11.1"
Inflector = "0.11.4"
lazy_static = "1.4.0"
serde = "1.0.122"
serde = "1.0.112"
serde_derive = "1.0.103"
serde_json = "1.0.56"
solana-config-program = { path = "../programs/config", version = "=1.6.3" }
solana-sdk = { path = "../sdk", version = "=1.6.3" }
solana-stake-program = { path = "../programs/stake", version = "=1.6.3" }
solana-vote-program = { path = "../programs/vote", version = "=1.6.3" }
spl-token-v2-0 = { package = "spl-token", version = "=3.1.0", features = ["no-entrypoint"] }
solana-config-program = { path = "../programs/config", version = "1.5.7" }
solana-sdk = { path = "../sdk", version = "1.5.7" }
solana-stake-program = { path = "../programs/stake", version = "1.5.7" }
solana-vote-program = { path = "../programs/vote", version = "1.5.7" }
spl-token-v2-0 = { package = "spl-token", version = "=3.0.1", features = ["no-entrypoint"] }
thiserror = "1.0"
zstd = "0.5.1"

View File

@@ -1,4 +1,3 @@
#![allow(clippy::integer_arithmetic)]
#[macro_use]
extern crate lazy_static;
#[macro_use]
@@ -16,10 +15,7 @@ pub mod validator_info;
use {
crate::parse_account_data::{parse_account_data, AccountAdditionalData, ParsedAccount},
solana_sdk::{
account::ReadableAccount, account::WritableAccount, clock::Epoch,
fee_calculator::FeeCalculator, pubkey::Pubkey,
},
solana_sdk::{account::Account, clock::Epoch, fee_calculator::FeeCalculator, pubkey::Pubkey},
std::{
io::{Read, Write},
str::FromStr,
@@ -27,7 +23,6 @@ use {
};
pub type StringAmount = String;
pub type StringDecimals = String;
/// A duplicate representation of an Account for pretty JSON serialization
#[derive(Serialize, Deserialize, Clone, Debug)]
@@ -60,61 +55,58 @@ pub enum UiAccountEncoding {
}
impl UiAccount {
pub fn encode<T: ReadableAccount>(
pub fn encode(
pubkey: &Pubkey,
account: T,
account: Account,
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 {
UiAccountData::Binary(
base64::encode(&account.data()),
UiAccountEncoding::Base64,
)
UiAccountData::Binary(base64::encode(&account.data), UiAccountEncoding::Base64)
}
}
};
UiAccount {
lamports: account.lamports(),
lamports: account.lamports,
data,
owner: account.owner().to_string(),
executable: account.executable(),
rent_epoch: account.rent_epoch(),
owner: account.owner.to_string(),
executable: account.executable,
rent_epoch: account.rent_epoch,
}
}
pub fn decode<T: WritableAccount>(&self) -> Option<T> {
pub fn decode(&self) -> Option<Account> {
let data = match &self.data {
UiAccountData::Json(_) => None,
UiAccountData::LegacyBinary(blob) => bs58::decode(blob).into_vec().ok(),
@@ -134,13 +126,13 @@ impl UiAccount {
UiAccountEncoding::Binary | UiAccountEncoding::JsonParsed => None,
},
}?;
Some(T::create(
self.lamports,
Some(Account {
lamports: self.lamports,
data,
Pubkey::from_str(&self.owner).ok()?,
self.executable,
self.rent_epoch,
))
owner: Pubkey::from_str(&self.owner).ok()?,
executable: self.executable,
rent_epoch: self.rent_epoch,
})
}
}
@@ -190,7 +182,6 @@ fn slice_data(data: &[u8], data_slice_config: Option<UiDataSliceConfig>) -> &[u8
#[cfg(test)]
mod test {
use super::*;
use solana_sdk::account::{Account, AccountSharedData};
#[test]
fn test_slice_data() {
@@ -224,10 +215,10 @@ mod test {
fn test_base64_zstd() {
let encoded_account = UiAccount::encode(
&Pubkey::default(),
AccountSharedData::from(Account {
Account {
data: vec![0; 1024],
..Account::default()
}),
},
UiAccountEncoding::Base64Zstd,
None,
None,
@@ -237,9 +228,7 @@ mod test {
UiAccountData::Binary(_, UiAccountEncoding::Base64Zstd)
));
let decoded_account = encoded_account.decode::<Account>().unwrap();
assert_eq!(decoded_account.data(), &vec![0; 1024]);
let decoded_account = encoded_account.decode::<AccountSharedData>().unwrap();
assert_eq!(decoded_account.data(), &vec![0; 1024]);
let decoded_account = encoded_account.decode().unwrap();
assert_eq!(decoded_account.data, vec![0; 1024]);
}
}

View File

@@ -91,7 +91,6 @@ mod test {
use crate::validator_info::ValidatorInfo;
use serde_json::json;
use solana_config_program::create_config_account;
use solana_sdk::account::ReadableAccount;
#[test]
fn test_parse_config() {
@@ -102,7 +101,7 @@ mod test {
let stake_config_account = create_config_account(vec![], &stake_config, 10);
assert_eq!(
parse_config(
&stake_config_account.data(),
&stake_config_account.data,
&solana_stake_program::config::id()
)
.unwrap(),
@@ -125,7 +124,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

@@ -214,13 +214,13 @@ pub struct UiStakeHistoryEntry {
mod test {
use super::*;
use solana_sdk::{
account::create_account_for_test, fee_calculator::FeeCalculator, hash::Hash,
account::create_account, fee_calculator::FeeCalculator, hash::Hash,
sysvar::recent_blockhashes::IterItem,
};
#[test]
fn test_parse_sysvars() {
let clock_sysvar = create_account_for_test(&Clock::default());
let clock_sysvar = create_account(&Clock::default(), 1);
assert_eq!(
parse_sysvar(&clock_sysvar.data, &sysvar::clock::id()).unwrap(),
SysvarAccountType::Clock(UiClock::default()),
@@ -233,13 +233,13 @@ mod test {
first_normal_epoch: 1,
first_normal_slot: 12,
};
let epoch_schedule_sysvar = create_account_for_test(&epoch_schedule);
let epoch_schedule_sysvar = create_account(&epoch_schedule, 1);
assert_eq!(
parse_sysvar(&epoch_schedule_sysvar.data, &sysvar::epoch_schedule::id()).unwrap(),
SysvarAccountType::EpochSchedule(epoch_schedule),
);
let fees_sysvar = create_account_for_test(&Fees::default());
let fees_sysvar = create_account(&Fees::default(), 1);
assert_eq!(
parse_sysvar(&fees_sysvar.data, &sysvar::fees::id()).unwrap(),
SysvarAccountType::Fees(UiFees::default()),
@@ -252,7 +252,7 @@ mod test {
let recent_blockhashes: RecentBlockhashes = vec![IterItem(0, &hash, &fee_calculator)]
.into_iter()
.collect();
let recent_blockhashes_sysvar = create_account_for_test(&recent_blockhashes);
let recent_blockhashes_sysvar = create_account(&recent_blockhashes, 1);
assert_eq!(
parse_sysvar(
&recent_blockhashes_sysvar.data,
@@ -270,13 +270,13 @@ mod test {
exemption_threshold: 2.0,
burn_percent: 5,
};
let rent_sysvar = create_account_for_test(&rent);
let rent_sysvar = create_account(&rent, 1);
assert_eq!(
parse_sysvar(&rent_sysvar.data, &sysvar::rent::id()).unwrap(),
SysvarAccountType::Rent(rent.into()),
);
let rewards_sysvar = create_account_for_test(&Rewards::default());
let rewards_sysvar = create_account(&Rewards::default(), 1);
assert_eq!(
parse_sysvar(&rewards_sysvar.data, &sysvar::rewards::id()).unwrap(),
SysvarAccountType::Rewards(UiRewards::default()),
@@ -284,7 +284,7 @@ mod test {
let mut slot_hashes = SlotHashes::default();
slot_hashes.add(1, hash);
let slot_hashes_sysvar = create_account_for_test(&slot_hashes);
let slot_hashes_sysvar = create_account(&slot_hashes, 1);
assert_eq!(
parse_sysvar(&slot_hashes_sysvar.data, &sysvar::slot_hashes::id()).unwrap(),
SysvarAccountType::SlotHashes(vec![UiSlotHashEntry {
@@ -295,7 +295,7 @@ mod test {
let mut slot_history = SlotHistory::default();
slot_history.add(42);
let slot_history_sysvar = create_account_for_test(&slot_history);
let slot_history_sysvar = create_account(&slot_history, 1);
assert_eq!(
parse_sysvar(&slot_history_sysvar.data, &sysvar::slot_history::id()).unwrap(),
SysvarAccountType::SlotHistory(UiSlotHistory {
@@ -311,7 +311,7 @@ mod test {
deactivating: 3,
};
stake_history.add(1, stake_history_entry.clone());
let stake_history_sysvar = create_account_for_test(&stake_history);
let stake_history_sysvar = create_account(&stake_history, 1);
assert_eq!(
parse_sysvar(&stake_history_sysvar.data, &sysvar::stake_history::id()).unwrap(),
SysvarAccountType::StakeHistory(vec![UiStakeHistoryEntry {

View File

@@ -1,6 +1,6 @@
use crate::{
parse_account_data::{ParsableAccount, ParseAccountError},
StringAmount, StringDecimals,
StringAmount,
};
use solana_sdk::pubkey::Pubkey;
use spl_token_v2_0::{
@@ -158,66 +158,46 @@ impl From<AccountState> for UiAccountState {
}
}
pub fn real_number_string(amount: u64, decimals: u8) -> StringDecimals {
let decimals = decimals as usize;
if decimals > 0 {
// Left-pad zeros to decimals + 1, so we at least have an integer zero
let mut s = format!("{:01$}", amount, decimals + 1);
// Add the decimal point (Sorry, "," locales!)
s.insert(s.len() - decimals, '.');
s
} else {
amount.to_string()
}
}
pub fn real_number_string_trimmed(amount: u64, decimals: u8) -> StringDecimals {
let mut s = real_number_string(amount, decimals);
if decimals > 0 {
let zeros_trimmed = s.trim_end_matches('0');
s = zeros_trimmed.trim_end_matches('.').to_string();
}
s
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct UiTokenAmount {
pub ui_amount: Option<f64>,
pub ui_amount: f64,
pub decimals: u8,
pub amount: StringAmount,
pub ui_amount_string: StringDecimals,
}
impl UiTokenAmount {
pub fn real_number_string(&self) -> String {
real_number_string(
u64::from_str(&self.amount).unwrap_or_default(),
self.decimals as u8,
)
let decimals = self.decimals as usize;
if decimals > 0 {
let amount = u64::from_str(&self.amount).unwrap_or(0);
// Left-pad zeros to decimals + 1, so we at least have an integer zero
let mut s = format!("{:01$}", amount, decimals + 1);
// Add the decimal point (Sorry, "," locales!)
s.insert(s.len() - decimals, '.');
s
} else {
self.amount.clone()
}
}
pub fn real_number_string_trimmed(&self) -> String {
if !self.ui_amount_string.is_empty() {
self.ui_amount_string.clone()
} else {
real_number_string_trimmed(
u64::from_str(&self.amount).unwrap_or_default(),
self.decimals as u8,
)
}
let s = self.real_number_string();
let zeros_trimmed = s.trim_end_matches('0');
let decimal_trimmed = zeros_trimmed.trim_end_matches('.');
decimal_trimmed.to_string()
}
}
pub fn token_amount_to_ui_amount(amount: u64, decimals: u8) -> UiTokenAmount {
let amount_decimals = 10_usize
.checked_pow(decimals as u32)
.map(|dividend| amount as f64 / dividend as f64);
// Use `amount_to_ui_amount()` once spl_token is bumped to a version that supports it: https://github.com/solana-labs/solana-program-library/pull/211
let amount_decimals = amount as f64 / 10_usize.pow(decimals as u32) as f64;
UiTokenAmount {
ui_amount: amount_decimals,
decimals,
amount: amount.to_string(),
ui_amount_string: real_number_string_trimmed(amount, decimals),
}
}
@@ -273,10 +253,9 @@ mod test {
mint: mint_pubkey.to_string(),
owner: owner_pubkey.to_string(),
token_amount: UiTokenAmount {
ui_amount: Some(0.42),
ui_amount: 0.42,
decimals: 2,
amount: "42".to_string(),
ui_amount_string: "0.42".to_string()
amount: "42".to_string()
},
delegate: None,
state: UiAccountState::Initialized,
@@ -357,87 +336,17 @@ mod test {
#[test]
fn test_ui_token_amount_real_string() {
assert_eq!(&real_number_string(1, 0), "1");
assert_eq!(&real_number_string_trimmed(1, 0), "1");
let token_amount = token_amount_to_ui_amount(1, 0);
assert_eq!(
token_amount.ui_amount_string,
real_number_string_trimmed(1, 0)
);
assert_eq!(token_amount.ui_amount, Some(1.0));
assert_eq!(&real_number_string(10, 0), "10");
assert_eq!(&real_number_string_trimmed(10, 0), "10");
let token_amount = token_amount_to_ui_amount(10, 0);
assert_eq!(
token_amount.ui_amount_string,
real_number_string_trimmed(10, 0)
);
assert_eq!(token_amount.ui_amount, Some(10.0));
assert_eq!(&real_number_string(1, 9), "0.000000001");
assert_eq!(&real_number_string_trimmed(1, 9), "0.000000001");
assert_eq!(&token_amount.real_number_string(), "1");
assert_eq!(&token_amount.real_number_string_trimmed(), "1");
let token_amount = token_amount_to_ui_amount(1, 9);
assert_eq!(
token_amount.ui_amount_string,
real_number_string_trimmed(1, 9)
);
assert_eq!(token_amount.ui_amount, Some(0.000000001));
assert_eq!(&real_number_string(1_000_000_000, 9), "1.000000000");
assert_eq!(&real_number_string_trimmed(1_000_000_000, 9), "1");
assert_eq!(&token_amount.real_number_string(), "0.000000001");
assert_eq!(&token_amount.real_number_string_trimmed(), "0.000000001");
let token_amount = token_amount_to_ui_amount(1_000_000_000, 9);
assert_eq!(
token_amount.ui_amount_string,
real_number_string_trimmed(1_000_000_000, 9)
);
assert_eq!(token_amount.ui_amount, Some(1.0));
assert_eq!(&real_number_string(1_234_567_890, 3), "1234567.890");
assert_eq!(&real_number_string_trimmed(1_234_567_890, 3), "1234567.89");
assert_eq!(&token_amount.real_number_string(), "1.000000000");
assert_eq!(&token_amount.real_number_string_trimmed(), "1");
let token_amount = token_amount_to_ui_amount(1_234_567_890, 3);
assert_eq!(
token_amount.ui_amount_string,
real_number_string_trimmed(1_234_567_890, 3)
);
assert_eq!(token_amount.ui_amount, Some(1234567.89));
assert_eq!(
&real_number_string(1_234_567_890, 25),
"0.0000000000000001234567890"
);
assert_eq!(
&real_number_string_trimmed(1_234_567_890, 25),
"0.000000000000000123456789"
);
let token_amount = token_amount_to_ui_amount(1_234_567_890, 20);
assert_eq!(
token_amount.ui_amount_string,
real_number_string_trimmed(1_234_567_890, 20)
);
assert_eq!(token_amount.ui_amount, None);
}
#[test]
fn test_ui_token_amount_real_string_zero() {
assert_eq!(&real_number_string(0, 0), "0");
assert_eq!(&real_number_string_trimmed(0, 0), "0");
let token_amount = token_amount_to_ui_amount(0, 0);
assert_eq!(
token_amount.ui_amount_string,
real_number_string_trimmed(0, 0)
);
assert_eq!(token_amount.ui_amount, Some(0.0));
assert_eq!(&real_number_string(0, 9), "0.000000000");
assert_eq!(&real_number_string_trimmed(0, 9), "0");
let token_amount = token_amount_to_ui_amount(0, 9);
assert_eq!(
token_amount.ui_amount_string,
real_number_string_trimmed(0, 9)
);
assert_eq!(token_amount.ui_amount, Some(0.0));
assert_eq!(&real_number_string(0, 25), "0.0000000000000000000000000");
assert_eq!(&real_number_string_trimmed(0, 25), "0");
let token_amount = token_amount_to_ui_amount(0, 20);
assert_eq!(
token_amount.ui_amount_string,
real_number_string_trimmed(0, 20)
);
assert_eq!(token_amount.ui_amount, None);
assert_eq!(&token_amount.real_number_string(), "1234567.890");
assert_eq!(&token_amount.real_number_string_trimmed(), "1234567.89");
}
}

View File

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

View File

@@ -1,4 +1,3 @@
#![allow(clippy::integer_arithmetic)]
#[macro_use]
extern crate log;
use clap::{crate_description, crate_name, value_t, App, Arg};
@@ -103,15 +102,17 @@ fn main() {
} else {
let mut pubkeys: Vec<Pubkey> = vec![];
let mut time = Measure::start("hash");
let results = accounts.accounts_db.update_accounts_hash(0, &ancestors);
let results = accounts
.accounts_db
.update_accounts_hash(0, &ancestors, true);
time.stop();
let mut time_store = Measure::start("hash using store");
let results_store = accounts.accounts_db.update_accounts_hash_with_index_option(
false,
true,
false,
solana_sdk::clock::Slot::default(),
&ancestors,
None,
true,
);
time_store.stop();
if results != results_store {

View File

@@ -1 +0,0 @@
/farf/

View File

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

View File

@@ -1,716 +0,0 @@
#![allow(clippy::integer_arithmetic)]
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_measure::measure::Measure;
use solana_runtime::inline_spl_token_v2_0;
use solana_sdk::{
commitment_config::CommitmentConfig,
message::Message,
pubkey::Pubkey,
rpc_port::DEFAULT_RPC_PORT,
signature::{read_keypair_file, Keypair, Signature, Signer},
system_instruction, system_program,
timing::timestamp,
transaction::Transaction,
};
use solana_transaction_status::parse_token::spl_token_v2_0_instruction;
use std::{
net::SocketAddr,
process::exit,
sync::{
atomic::{AtomicBool, AtomicU64, Ordering},
Arc, RwLock,
},
thread::{sleep, Builder, JoinHandle},
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,
id: &Keypair,
desired_balance: u64,
) -> bool {
let starting_balance = client.get_balance(&id.pubkey()).unwrap_or(0);
info!("starting balance {}", starting_balance);
if starting_balance < desired_balance {
let airdrop_amount = desired_balance - starting_balance;
info!(
"Airdropping {:?} lamports from {} for {}",
airdrop_amount,
faucet_addr,
id.pubkey(),
);
let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap();
match request_airdrop_transaction(&faucet_addr, &id.pubkey(), airdrop_amount, blockhash) {
Ok(transaction) => {
let mut tries = 0;
loop {
tries += 1;
let result = client.send_and_confirm_transaction(&transaction);
if result.is_ok() {
break;
}
if tries >= 5 {
panic!(
"Error requesting airdrop: to addr: {:?} amount: {} {:?}",
faucet_addr, airdrop_amount, result
)
}
}
}
Err(err) => {
panic!(
"Error requesting airdrop: {:?} to addr: {:?} amount: {}",
err, faucet_addr, airdrop_amount
);
}
};
let current_balance = client.get_balance(&id.pubkey()).unwrap_or_else(|e| {
panic!("airdrop error {}", e);
});
info!("current balance {}...", current_balance);
if current_balance - starting_balance != airdrop_amount {
info!(
"Airdrop failed? {} {} {} {}",
id.pubkey(),
current_balance,
starting_balance,
airdrop_amount,
);
}
}
true
}
// signature, timestamp, id
type PendingQueue = Vec<(Signature, u64, u64)>;
struct TransactionExecutor {
sig_clear_t: JoinHandle<()>,
sigs: Arc<RwLock<PendingQueue>>,
cleared: Arc<RwLock<Vec<u64>>>,
exit: Arc<AtomicBool>,
counter: AtomicU64,
client: RpcClient,
}
impl TransactionExecutor {
fn new(entrypoint_addr: SocketAddr) -> Self {
let sigs = Arc::new(RwLock::new(Vec::new()));
let cleared = Arc::new(RwLock::new(Vec::new()));
let exit = Arc::new(AtomicBool::new(false));
let sig_clear_t = Self::start_sig_clear_thread(&exit, &sigs, &cleared, entrypoint_addr);
let client =
RpcClient::new_socket_with_commitment(entrypoint_addr, CommitmentConfig::confirmed());
Self {
sigs,
cleared,
sig_clear_t,
exit,
counter: AtomicU64::new(0),
client,
}
}
fn num_outstanding(&self) -> usize {
self.sigs.read().unwrap().len()
}
fn push_transactions(&self, txs: Vec<Transaction>) -> Vec<u64> {
let mut ids = vec![];
let new_sigs = txs.into_iter().filter_map(|tx| {
let id = self.counter.fetch_add(1, Ordering::Relaxed);
ids.push(id);
match self.client.send_transaction(&tx) {
Ok(sig) => {
return Some((sig, timestamp(), id));
}
Err(e) => {
info!("error: {:#?}", e);
}
}
None
});
let mut sigs_w = self.sigs.write().unwrap();
sigs_w.extend(new_sigs);
ids
}
fn drain_cleared(&self) -> Vec<u64> {
std::mem::take(&mut *self.cleared.write().unwrap())
}
fn close(self) {
self.exit.store(true, Ordering::Relaxed);
self.sig_clear_t.join().unwrap();
}
fn start_sig_clear_thread(
exit: &Arc<AtomicBool>,
sigs: &Arc<RwLock<PendingQueue>>,
cleared: &Arc<RwLock<Vec<u64>>>,
entrypoint_addr: SocketAddr,
) -> JoinHandle<()> {
let sigs = sigs.clone();
let exit = exit.clone();
let cleared = cleared.clone();
Builder::new()
.name("sig_clear".to_string())
.spawn(move || {
let client = RpcClient::new_socket_with_commitment(
entrypoint_addr,
CommitmentConfig::confirmed(),
);
let mut success = 0;
let mut error_count = 0;
let mut timed_out = 0;
let mut last_log = Instant::now();
while !exit.load(Ordering::Relaxed) {
let sigs_len = sigs.read().unwrap().len();
if sigs_len > 0 {
let mut sigs_w = sigs.write().unwrap();
let mut start = Measure::start("sig_status");
let statuses: Vec<_> = sigs_w
.chunks(200)
.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();
let now = timestamp();
let mut new_ids = vec![];
let mut i = 0;
let mut j = 0;
while i != sigs_w.len() {
let mut retain = true;
let sent_ts = sigs_w[i].1;
if let Some(e) = &statuses[j] {
debug!("error: {:?}", e);
if e.status.is_ok() {
success += 1;
} else {
error_count += 1;
}
num_cleared += 1;
retain = false;
} else if now - sent_ts > 30_000 {
retain = false;
timed_out += 1;
}
if !retain {
new_ids.push(sigs_w.remove(i).2);
} else {
i += 1;
}
j += 1;
}
let final_sigs_len = sigs_w.len();
drop(sigs_w);
cleared.write().unwrap().extend(new_ids);
start.stop();
debug!(
"sigs len: {:?} success: {} took: {}ms cleared: {}/{}",
final_sigs_len,
success,
start.as_ms(),
num_cleared,
start_len,
);
if last_log.elapsed().as_millis() > 5000 {
info!(
"success: {} error: {} timed_out: {}",
success, error_count, timed_out,
);
last_log = Instant::now();
}
}
sleep(Duration::from_millis(200));
}
})
.unwrap()
}
}
struct SeedTracker {
max_created: Arc<AtomicU64>,
max_closed: Arc<AtomicU64>,
}
fn make_create_message(
keypair: &Keypair,
base_keypair: &Keypair,
max_created_seed: Arc<AtomicU64>,
num_instructions: usize,
balance: u64,
maybe_space: Option<u64>,
mint: Option<Pubkey>,
) -> Message {
let space = maybe_space.unwrap_or_else(|| thread_rng().gen_range(0, 1000));
let instructions: Vec<_> = (0..num_instructions)
.into_iter()
.map(|_| {
let program_id = if mint.is_some() {
inline_spl_token_v2_0::id()
} else {
system_program::id()
};
let seed = max_created_seed.fetch_add(1, Ordering::Relaxed).to_string();
let to_pubkey =
Pubkey::create_with_seed(&base_keypair.pubkey(), &seed, &program_id).unwrap();
let mut instructions = vec![system_instruction::create_account_with_seed(
&keypair.pubkey(),
&to_pubkey,
&base_keypair.pubkey(),
&seed,
balance,
space,
&program_id,
)];
if let Some(mint_address) = mint {
instructions.push(spl_token_v2_0_instruction(
spl_token_v2_0::instruction::initialize_account(
&spl_token_v2_0::id(),
&spl_token_v2_0_pubkey(&to_pubkey),
&spl_token_v2_0_pubkey(&mint_address),
&spl_token_v2_0_pubkey(&base_keypair.pubkey()),
)
.unwrap(),
));
}
instructions
})
.collect();
let instructions: Vec<_> = instructions.into_iter().flatten().collect();
Message::new(&instructions, Some(&keypair.pubkey()))
}
fn make_close_message(
keypair: &Keypair,
base_keypair: &Keypair,
max_closed_seed: Arc<AtomicU64>,
num_instructions: usize,
balance: u64,
spl_token: bool,
) -> Message {
let instructions: Vec<_> = (0..num_instructions)
.into_iter()
.map(|_| {
let program_id = if spl_token {
inline_spl_token_v2_0::id()
} else {
system_program::id()
};
let seed = max_closed_seed.fetch_add(1, Ordering::Relaxed).to_string();
let address =
Pubkey::create_with_seed(&base_keypair.pubkey(), &seed, &program_id).unwrap();
if spl_token {
spl_token_v2_0_instruction(
spl_token_v2_0::instruction::close_account(
&spl_token_v2_0::id(),
&spl_token_v2_0_pubkey(&address),
&spl_token_v2_0_pubkey(&keypair.pubkey()),
&spl_token_v2_0_pubkey(&base_keypair.pubkey()),
&[],
)
.unwrap(),
)
} else {
system_instruction::transfer_with_seed(
&address,
&base_keypair.pubkey(),
seed,
&program_id,
&keypair.pubkey(),
balance,
)
}
})
.collect();
Message::new(&instructions, Some(&keypair.pubkey()))
}
#[allow(clippy::too_many_arguments)]
fn run_accounts_bench(
entrypoint_addr: SocketAddr,
faucet_addr: SocketAddr,
keypair: &Keypair,
iterations: usize,
maybe_space: Option<u64>,
batch_size: usize,
close_nth: u64,
maybe_lamports: Option<u64>,
num_instructions: usize,
mint: Option<Pubkey>,
) {
assert!(num_instructions > 0);
let client =
RpcClient::new_socket_with_commitment(entrypoint_addr, CommitmentConfig::confirmed());
info!("Targetting {}", entrypoint_addr);
let mut last_blockhash = Instant::now();
let mut last_log = Instant::now();
let mut count = 0;
let mut recent_blockhash = client.get_recent_blockhash().expect("blockhash");
let mut tx_sent_count = 0;
let mut total_accounts_created = 0;
let mut total_accounts_closed = 0;
let mut balance = client.get_balance(&keypair.pubkey()).unwrap_or(0);
let mut last_balance = Instant::now();
let default_max_lamports = 1000;
let min_balance = maybe_lamports.unwrap_or_else(|| {
let space = maybe_space.unwrap_or(default_max_lamports);
client
.get_minimum_balance_for_rent_exemption(space as usize)
.expect("min balance")
});
let base_keypair = Keypair::new();
let seed_tracker = SeedTracker {
max_created: Arc::new(AtomicU64::default()),
max_closed: Arc::new(AtomicU64::default()),
};
info!("Starting balance: {}", balance);
let executor = TransactionExecutor::new(entrypoint_addr);
loop {
if last_blockhash.elapsed().as_millis() > 10_000 {
recent_blockhash = client.get_recent_blockhash().expect("blockhash");
last_blockhash = Instant::now();
}
let fee = recent_blockhash
.1
.lamports_per_signature
.saturating_mul(NUM_SIGNATURES);
let lamports = min_balance + fee;
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;
}
}
}
let sigs_len = executor.num_outstanding();
if sigs_len < batch_size {
let num_to_create = batch_size - sigs_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 > 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(
keypair,
&base_keypair,
seed_tracker.max_closed.clone(),
1,
min_balance,
mint.is_some(),
);
let signers: Vec<&Keypair> = vec![keypair, &base_keypair];
Transaction::new(&signers, message, recent_blockhash.0)
})
.collect();
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());
tx_sent_count += new_ids.len();
total_accounts_closed += new_ids.len() as u64;
}
}
} else {
let _ = executor.drain_cleared();
}
count += 1;
if last_log.elapsed().as_millis() > 3000 {
info!(
"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();
}
if iterations != 0 && count >= iterations {
break;
}
if executor.num_outstanding() >= batch_size {
sleep(Duration::from_millis(500));
}
}
executor.close();
}
fn main() {
solana_logger::setup_with_default("solana=info");
let matches = App::new(crate_name!())
.about(crate_description!())
.version(solana_version::version!())
.arg(
Arg::with_name("entrypoint")
.long("entrypoint")
.takes_value(true)
.value_name("HOST:PORT")
.help("RPC entrypoint address. Usually <ip>:8899"),
)
.arg(
Arg::with_name("faucet_addr")
.long("faucet")
.takes_value(true)
.value_name("HOST:PORT")
.help("Faucet entrypoint address. Usually <ip>:9900"),
)
.arg(
Arg::with_name("space")
.long("space")
.takes_value(true)
.value_name("BYTES")
.help("Size of accounts to create"),
)
.arg(
Arg::with_name("lamports")
.long("lamports")
.takes_value(true)
.value_name("LAMPORTS")
.help("How many lamports to fund each account"),
)
.arg(
Arg::with_name("identity")
.long("identity")
.takes_value(true)
.value_name("FILE")
.help("keypair file"),
)
.arg(
Arg::with_name("batch_size")
.long("batch-size")
.takes_value(true)
.value_name("BYTES")
.help("Number of transactions to send per batch"),
)
.arg(
Arg::with_name("close_nth")
.long("close-frequency")
.takes_value(true)
.value_name("BYTES")
.help(
"Send close transactions after this many accounts created. \
Note: a `close-frequency` value near or below `batch-size` \
may result in transaction-simulation errors, as the close \
transactions will be submitted before the corresponding \
create transactions have been confirmed",
),
)
.arg(
Arg::with_name("num_instructions")
.long("num-instructions")
.takes_value(true)
.value_name("NUM")
.help("Number of accounts to create on each transaction"),
)
.arg(
Arg::with_name("iterations")
.long("iterations")
.takes_value(true)
.value_name("NUM")
.help("Number of iterations to make"),
)
.arg(
Arg::with_name("check_gossip")
.long("check-gossip")
.help("Just use entrypoint address directly"),
)
.arg(
Arg::with_name("mint")
.long("mint")
.takes_value(true)
.help("Mint address to initialize account"),
)
.get_matches();
let skip_gossip = !matches.is_present("check_gossip");
let port = if skip_gossip { DEFAULT_RPC_PORT } else { 8001 };
let mut entrypoint_addr = SocketAddr::from(([127, 0, 0, 1], port));
if let Some(addr) = matches.value_of("entrypoint") {
entrypoint_addr = solana_net_utils::parse_host_port(addr).unwrap_or_else(|e| {
eprintln!("failed to parse entrypoint address: {}", e);
exit(1)
});
}
let mut faucet_addr = SocketAddr::from(([127, 0, 0, 1], FAUCET_PORT));
if let Some(addr) = matches.value_of("faucet_addr") {
faucet_addr = solana_net_utils::parse_host_port(addr).unwrap_or_else(|e| {
eprintln!("failed to parse entrypoint address: {}", e);
exit(1)
});
}
let space = value_t!(matches, "space", u64).ok();
let lamports = value_t!(matches, "lamports", u64).ok();
let batch_size = value_t!(matches, "batch_size", usize).unwrap_or(4);
let close_nth = value_t!(matches, "close_nth", u64).unwrap_or(0);
let 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 {
eprintln!("bad num_instructions: {}", num_instructions);
exit(1);
}
let mint = pubkey_of(&matches, "mint");
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,
Some(&entrypoint_addr),
None,
Some(60),
None,
Some(&entrypoint_addr),
None,
0,
)
.unwrap_or_else(|err| {
eprintln!("Failed to discover {} node: {:?}", entrypoint_addr, err);
exit(1);
});
info!("done found {} nodes", gossip_nodes.len());
gossip_nodes[0].rpc
} else {
info!("Using {:?} as the RPC address", entrypoint_addr);
entrypoint_addr
};
run_accounts_bench(
rpc_addr,
faucet_addr,
&keypair,
iterations,
space,
batch_size,
close_nth,
lamports,
num_instructions,
mint,
);
}
#[cfg(test)]
pub mod test {
use super::*;
use solana_core::validator::ValidatorConfig;
use solana_local_cluster::{
local_cluster::{ClusterConfig, LocalCluster},
validator_configs::make_identical_validator_configs,
};
use solana_sdk::poh_config::PohConfig;
#[test]
fn test_accounts_cluster_bench() {
solana_logger::setup();
let validator_config = ValidatorConfig::default();
let num_nodes = 1;
let mut config = ClusterConfig {
cluster_lamports: 10_000_000,
poh_config: PohConfig::new_sleep(Duration::from_millis(50)),
node_stakes: vec![100; num_nodes],
validator_configs: make_identical_validator_configs(&validator_config, num_nodes),
..ClusterConfig::default()
};
let faucet_addr = SocketAddr::from(([127, 0, 0, 1], 9900));
let cluster = LocalCluster::new(&mut config);
let iterations = 10;
let maybe_space = None;
let batch_size = 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,
iterations,
maybe_space,
batch_size,
close_nth,
maybe_lamports,
num_instructions,
None,
);
start.stop();
info!("{}", start);
}
}

View File

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

View File

@@ -1,4 +1,3 @@
#![allow(clippy::integer_arithmetic)]
use clap::{crate_description, crate_name, value_t, App, Arg};
use crossbeam_channel::unbounded;
use log::*;
@@ -19,7 +18,7 @@ use solana_ledger::{
use solana_measure::measure::Measure;
use solana_perf::packet::to_packets_chunked;
use solana_runtime::{
accounts_background_service::AbsRequestSender, bank::Bank, bank_forks::BankForks,
accounts_background_service::ABSRequestSender, bank::Bank, bank_forks::BankForks,
};
use solana_sdk::{
hash::Hash,
@@ -326,7 +325,7 @@ fn main() {
poh_recorder.lock().unwrap().set_bank(&bank);
assert!(poh_recorder.lock().unwrap().bank().is_some());
if bank.slot() > 32 {
bank_forks.set_root(root, &AbsRequestSender::default(), None);
bank_forks.set_root(root, &ABSRequestSender::default(), None);
root += 1;
}
debug!(

View File

@@ -1,30 +1,26 @@
[package]
name = "solana-banks-client"
version = "1.6.3"
version = "1.5.7"
description = "Solana banks client"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-banks-client"
edition = "2018"
[dependencies]
bincode = "1.3.1"
borsh = "0.8.1"
borsh-derive = "0.8.1"
futures = "0.3"
mio = "0.7.6"
solana-banks-interface = { path = "../banks-interface", version = "=1.6.3" }
solana-program = { path = "../sdk/program", version = "=1.6.3" }
solana-sdk = { path = "../sdk", version = "=1.6.3" }
tarpc = { version = "0.24.1", features = ["full"] }
tokio = { version = "1.1", features = ["full"] }
tokio-serde = { version = "0.8", features = ["bincode"] }
solana-banks-interface = { path = "../banks-interface", version = "1.5.7" }
solana-sdk = { path = "../sdk", version = "1.5.7" }
tarpc = { version = "0.23.0", features = ["full"] }
tokio = { version = "0.3.5", features = ["full"] }
tokio-serde = { version = "0.6", features = ["bincode"] }
[dev-dependencies]
solana-runtime = { path = "../runtime", version = "=1.6.3" }
solana-banks-server = { path = "../banks-server", version = "=1.6.3" }
solana-runtime = { path = "../runtime", version = "1.5.7" }
solana-banks-server = { path = "../banks-server", version = "1.5.7" }
[lib]
crate-type = ["lib"]

View File

@@ -5,18 +5,19 @@
//! but they are undocumented, may change over time, and are generally more
//! cumbersome to use.
use borsh::BorshDeserialize;
use futures::{future::join_all, Future, FutureExt};
pub use solana_banks_interface::{BanksClient as TarpcClient, TransactionStatus};
use solana_banks_interface::{BanksRequest, BanksResponse};
use solana_program::{
clock::Slot, fee_calculator::FeeCalculator, hash::Hash, program_pack::Pack, pubkey::Pubkey,
rent::Rent, sysvar,
};
use solana_sdk::{
account::{from_account, Account},
clock::Slot,
commitment_config::CommitmentLevel,
fee_calculator::FeeCalculator,
hash::Hash,
pubkey::Pubkey,
rent::Rent,
signature::Signature,
sysvar,
transaction::{self, Transaction},
transport,
};
@@ -129,7 +130,7 @@ impl BanksClient {
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(|| {
from_account::<Rent>(&rent_sysvar).ok_or_else(|| {
io::Error::new(io::ErrorKind::Other, "Failed to deserialize Rent sysvar")
})
})
@@ -217,33 +218,6 @@ impl BanksClient {
self.get_account_with_commitment(address, CommitmentLevel::default())
}
/// Return the unpacked account data at the given address
/// If the account is not found, an error is returned
pub fn get_packed_account_data<T: Pack>(
&mut self,
address: Pubkey,
) -> impl Future<Output = io::Result<T>> + '_ {
self.get_account(address).map(|result| {
let account =
result?.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Account not found"))?;
T::unpack_from_slice(&account.data)
.map_err(|_| io::Error::new(io::ErrorKind::Other, "Failed to deserialize account"))
})
}
/// Return the unpacked account data at the given address
/// If the account is not found, an error is returned
pub fn get_account_data_with_borsh<T: BorshDeserialize>(
&mut self,
address: Pubkey,
) -> impl Future<Output = io::Result<T>> + '_ {
self.get_account(address).map(|result| {
let account =
result?.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "account not found"))?;
T::try_from_slice(&account.data)
})
}
/// Return the balance in lamports of an account at the given address at the slot
/// corresponding to the given commitment level.
pub fn get_balance_with_commitment(

View File

@@ -1,22 +1,21 @@
[package]
name = "solana-banks-interface"
version = "1.6.3"
version = "1.5.7"
description = "Solana banks RPC interface"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-banks-interface"
edition = "2018"
[dependencies]
mio = "0.7.6"
serde = { version = "1.0.122", features = ["derive"] }
solana-sdk = { path = "../sdk", version = "=1.6.3" }
tarpc = { version = "0.24.1", features = ["full"] }
serde = { version = "1.0.112", features = ["derive"] }
solana-sdk = { path = "../sdk", version = "1.5.7" }
tarpc = { version = "0.23.0", features = ["full"] }
[dev-dependencies]
tokio = { version = "1.1", features = ["full"] }
tokio = { version = "0.3.5", features = ["full"] }
[lib]
crate-type = ["lib"]

View File

@@ -1,12 +1,11 @@
[package]
name = "solana-banks-server"
version = "1.6.3"
version = "1.5.7"
description = "Solana banks server"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-banks-server"
edition = "2018"
[dependencies]
@@ -14,14 +13,13 @@ bincode = "1.3.1"
futures = "0.3"
log = "0.4.11"
mio = "0.7.6"
solana-banks-interface = { path = "../banks-interface", version = "=1.6.3" }
solana-runtime = { path = "../runtime", version = "=1.6.3" }
solana-sdk = { path = "../sdk", version = "=1.6.3" }
solana-metrics = { path = "../metrics", version = "=1.6.3" }
tarpc = { version = "0.24.1", features = ["full"] }
tokio = { version = "1.1", features = ["full"] }
tokio-serde = { version = "0.8", features = ["bincode"] }
tokio-stream = "0.1"
solana-banks-interface = { path = "../banks-interface", version = "1.5.7" }
solana-runtime = { path = "../runtime", version = "1.5.7" }
solana-sdk = { path = "../sdk", version = "1.5.7" }
solana-metrics = { path = "../metrics", version = "1.5.7" }
tarpc = { version = "0.23.0", features = ["full"] }
tokio = { version = "0.3", features = ["full"] }
tokio-serde = { version = "0.6", features = ["bincode"] }
[lib]
crate-type = ["lib"]

View File

@@ -242,7 +242,7 @@ impl Banks for BanksServer {
commitment: CommitmentLevel,
) -> Option<Account> {
let bank = self.bank(commitment);
bank.get_account(&address).map(Account::from)
bank.get_account(&address)
}
}

View File

@@ -1,4 +1,3 @@
#![allow(clippy::integer_arithmetic)]
pub mod banks_server;
pub mod rpc_banks_service;
pub mod send_transaction_service;

View File

@@ -15,7 +15,6 @@ use tokio::{
runtime::Runtime,
time::{self, Duration},
};
use tokio_stream::wrappers::IntervalStream;
pub struct RpcBanksService {
thread_hdl: JoinHandle<()>,
@@ -36,7 +35,7 @@ async fn start_abortable_tcp_server(
block_commitment_cache.clone(),
)
.fuse();
let interval = IntervalStream::new(time::interval(Duration::from_millis(100))).fuse();
let interval = time::interval(Duration::from_millis(100)).fuse();
pin_mut!(server, interval);
loop {
select! {

View File

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

View File

@@ -1,5 +1,4 @@
#![allow(clippy::useless_attribute)]
#![allow(clippy::integer_arithmetic)]
use crate::order_book::*;
use itertools::izip;

View File

@@ -1,4 +1,3 @@
#![allow(clippy::integer_arithmetic)]
pub mod bench;
mod cli;
pub mod order_book;

View File

@@ -1,23 +1,19 @@
use log::*;
use solana_bench_exchange::bench::{airdrop_lamports, do_bench_exchange, Config};
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_core::gossip_service::{discover_cluster, get_multi_client};
use solana_core::validator::ValidatorConfig;
use solana_exchange_program::exchange_processor::process_instruction;
use solana_exchange_program::id;
use solana_exchange_program::solana_exchange_program;
use solana_faucet::faucet::run_local_faucet_with_port;
use solana_local_cluster::{
local_cluster::{ClusterConfig, LocalCluster},
validator_configs::make_identical_validator_configs,
};
use solana_runtime::{bank::Bank, bank_client::BankClient};
use solana_sdk::{
genesis_config::create_genesis_config,
signature::{Keypair, Signer},
};
use std::{process::exit, sync::mpsc::channel, time::Duration};
use solana_local_cluster::local_cluster::{ClusterConfig, LocalCluster};
use solana_runtime::bank::Bank;
use solana_runtime::bank_client::BankClient;
use solana_sdk::genesis_config::create_genesis_config;
use solana_sdk::signature::{Keypair, Signer};
use std::process::exit;
use std::sync::mpsc::channel;
use std::time::Duration;
#[test]
#[ignore]
@@ -48,7 +44,7 @@ fn test_exchange_local_cluster() {
let cluster = LocalCluster::new(&mut ClusterConfig {
node_stakes: vec![100_000; NUM_NODES],
cluster_lamports: 100_000_000_000_000,
validator_configs: make_identical_validator_configs(&ValidatorConfig::default(), NUM_NODES),
validator_configs: vec![ValidatorConfig::default(); NUM_NODES],
native_instruction_processors: [solana_exchange_program!()].to_vec(),
..ClusterConfig::default()
});

View File

@@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-bench-streamer"
version = "1.6.3"
version = "1.5.7"
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.6.3" }
solana-streamer = { path = "../streamer", version = "=1.6.3" }
solana-logger = { path = "../logger", version = "=1.6.3" }
solana-net-utils = { path = "../net-utils", version = "=1.6.3" }
solana-version = { path = "../version", version = "=1.6.3" }
solana-clap-utils = { path = "../clap-utils", version = "1.5.7" }
solana-streamer = { path = "../streamer", version = "1.5.7" }
solana-logger = { path = "../logger", version = "1.5.7" }
solana-net-utils = { path = "../net-utils", version = "1.5.7" }
solana-version = { path = "../version", version = "1.5.7" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -1,4 +1,3 @@
#![allow(clippy::integer_arithmetic)]
use clap::{crate_description, crate_name, App, Arg};
use solana_streamer::packet::{Packet, Packets, PacketsRecycler, PACKET_DATA_SIZE};
use solana_streamer::streamer::{receiver, PacketReceiver};
@@ -75,7 +74,7 @@ fn main() -> Result<()> {
let mut read_channels = Vec::new();
let mut read_threads = Vec::new();
let recycler = PacketsRecycler::new_without_limit("bench-streamer-recycler-shrink-stats");
let recycler = PacketsRecycler::default();
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();
@@ -91,7 +90,6 @@ fn main() -> Result<()> {
s_reader,
recycler.clone(),
"bench-streamer-test",
1,
));
}

View File

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

View File

@@ -8,7 +8,7 @@ use solana_measure::measure::Measure;
use solana_metrics::{self, datapoint_info};
use solana_sdk::{
client::Client,
clock::{DEFAULT_S_PER_SLOT, MAX_PROCESSING_AGE},
clock::{DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT, MAX_PROCESSING_AGE},
commitment_config::CommitmentConfig,
fee_calculator::FeeCalculator,
hash::Hash,
@@ -32,7 +32,8 @@ use std::{
};
// The point at which transactions become "too old", in seconds.
const MAX_TX_QUEUE_AGE: u64 = (MAX_PROCESSING_AGE as f64 * DEFAULT_S_PER_SLOT) as u64;
const MAX_TX_QUEUE_AGE: u64 =
MAX_PROCESSING_AGE as u64 * DEFAULT_TICKS_PER_SLOT / DEFAULT_TICKS_PER_SECOND;
pub const MAX_SPENDS_PER_TX: u64 = 4;

View File

@@ -1,3 +1,2 @@
#![allow(clippy::integer_arithmetic)]
pub mod bench;
pub mod cli;

View File

@@ -1,4 +1,3 @@
#![allow(clippy::integer_arithmetic)]
use log::*;
use solana_bench_tps::bench::{do_bench_tps, generate_and_fund_keypairs, generate_keypairs};
use solana_bench_tps::cli;

View File

@@ -1,21 +1,14 @@
#![allow(clippy::integer_arithmetic)]
use serial_test::serial;
use solana_bench_tps::{
bench::{do_bench_tps, generate_and_fund_keypairs},
cli::Config,
};
use serial_test_derive::serial;
use solana_bench_tps::bench::{do_bench_tps, generate_and_fund_keypairs};
use solana_bench_tps::cli::Config;
use solana_client::thin_client::create_client;
use solana_core::{cluster_info::VALIDATOR_PORT_RANGE, validator::ValidatorConfig};
use solana_core::cluster_info::VALIDATOR_PORT_RANGE;
use solana_core::validator::ValidatorConfig;
use solana_faucet::faucet::run_local_faucet_with_port;
use solana_local_cluster::{
local_cluster::{ClusterConfig, LocalCluster},
validator_configs::make_identical_validator_configs,
};
use solana_local_cluster::local_cluster::{ClusterConfig, LocalCluster};
use solana_sdk::signature::{Keypair, Signer};
use std::{
sync::{mpsc::channel, Arc},
time::Duration,
};
use std::sync::{mpsc::channel, Arc};
use std::time::Duration;
fn test_bench_tps_local_cluster(config: Config) {
let native_instruction_processors = vec![];
@@ -25,7 +18,7 @@ fn test_bench_tps_local_cluster(config: Config) {
let cluster = LocalCluster::new(&mut ClusterConfig {
node_stakes: vec![999_990; NUM_NODES],
cluster_lamports: 200_000_000,
validator_configs: make_identical_validator_configs(&ValidatorConfig::default(), NUM_NODES),
validator_configs: vec![ValidatorConfig::default(); NUM_NODES],
native_instruction_processors,
..ClusterConfig::default()
});

View File

@@ -1,45 +0,0 @@
#!/usr/bin/env bash
set -e
here="$(dirname "$0")"
src_root="$(readlink -f "${here}/..")"
cd "${src_root}"
source ci/rust-version.sh stable
cargo_audit_ignores=(
# failure is officially deprecated/unmaintained
#
# Blocked on multiple upstream crates removing their `failure` dependency.
--ignore RUSTSEC-2020-0036
# `net2` crate has been deprecated; use `socket2` instead
#
# Blocked on https://github.com/paritytech/jsonrpc/issues/575
--ignore RUSTSEC-2020-0016
# stdweb is unmaintained
#
# Blocked on multiple upstream crates removing their `stdweb` dependency.
--ignore RUSTSEC-2020-0056
# Potential segfault in the time crate
#
# Blocked on multiple crates updating `time` to >= 0.2.23
--ignore RUSTSEC-2020-0071
# difference is unmaintained
#
# Blocked on predicates v1.0.6 removing its dependency on `difference`
--ignore RUSTSEC-2020-0095
# generic-array: arr! macro erases lifetimes
#
# Blocked on libsecp256k1 releasing with upgraded dependencies
# https://github.com/paritytech/libsecp256k1/issues/66
--ignore RUSTSEC-2020-0146
)
scripts/cargo-for-all-lock-files.sh +"$rust_stable" audit "${cargo_audit_ignores[@]}"

View File

@@ -1,4 +1,4 @@
FROM solanalabs/rust:1.50.0
FROM solanalabs/rust:1.49.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.50.0
FROM rust:1.49.0
# Add Google Protocol Buffers for Libra's metrics library.
ENV PROTOC_VERSION 3.8.0

View File

@@ -78,8 +78,9 @@ nodes=(
--init-complete-file init-complete-node0.log \
--dynamic-port-range 8000-8050"
"multinode-demo/validator.sh \
--enable-rpc-exit \
--no-restart \
--dynamic-port-range 8050-8100
--dynamic-port-range 8050-8100 \
--init-complete-file init-complete-node1.log \
--rpc-port 18899"
)
@@ -200,10 +201,17 @@ killNodes() {
[[ ${#pids[@]} -gt 0 ]] || return
# Try to use the RPC exit API to cleanly exit the first two nodes
# (dynamic nodes, -x, are just killed)
# (dynamic nodes, -x, are just killed since their RPC port is not known)
echo "--- RPC exit"
$solana_validator --ledger "$SOLANA_CONFIG_DIR"/bootstrap-validator exit --force || true
$solana_validator --ledger "$SOLANA_CONFIG_DIR"/validator exit --force || true
for port in 8899 18899; do
(
set -x
curl --retry 5 --retry-delay 2 --retry-connrefused \
-X POST -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1, "method":"validatorExit"}' \
http://localhost:$port
)
done
# Give the nodes a splash of time to cleanly exit before killing them
sleep 2

View File

@@ -25,8 +25,7 @@ snapshot_slot=1
while [[ $($solana_cli --url http://localhost:8899 slot --commitment recent) -le $((snapshot_slot + 1)) ]]; do
sleep 1
done
$solana_validator --ledger config/ledger exit --force || true
curl -X POST -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":1, "method":"validatorExit"}' http://localhost:8899
wait $pid

View File

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

View File

@@ -12,16 +12,6 @@ cargo="$(readlink -f "./cargo")"
scripts/increment-cargo-version.sh check
# Disallow uncommitted Cargo.lock changes
(
_ 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
exit 1
fi
)
echo --- build environment
(
set -x
@@ -62,24 +52,54 @@ else
fi
_ ci/order-crates-for-publishing.py
_ "$cargo" stable fmt --all -- --check
# -Z... is needed because of clippy bug: https://github.com/rust-lang/rust-clippy/issues/4612
# run nightly clippy for `sdk/` as there's a moderate amount of nightly-only code there
_ "$cargo" nightly clippy -Zunstable-options --workspace --all-targets -- --deny=warnings --deny=clippy::integer_arithmetic
_ "$cargo" nightly clippy -Zunstable-options --workspace --all-targets -- --deny=warnings
_ "$cargo" stable fmt --all -- --check
cargo_audit_ignores=(
# failure is officially deprecated/unmaintained
#
# Blocked on multiple upstream crates removing their `failure` dependency.
--ignore RUSTSEC-2020-0036
_ ci/do-audit.sh
# `net2` crate has been deprecated; use `socket2` instead
#
# Blocked on https://github.com/paritytech/jsonrpc/issues/575
--ignore RUSTSEC-2020-0016
# stdweb is unmaintained
#
# Blocked on multiple upstream crates removing their `stdweb` dependency.
--ignore RUSTSEC-2020-0056
# Potential segfault in the time crate
#
# Blocked on multiple crates updating `time` to >= 0.2.23
--ignore RUSTSEC-2020-0071
# difference is unmaintained
#
# Blocked on predicates v1.0.6 removing its dependency on `difference`
--ignore RUSTSEC-2020-0095
# hyper is upgraded on master/v1.6 but not for v1.5
--ignore RUSTSEC-2021-0020
)
_ scripts/cargo-for-all-lock-files.sh +"$rust_stable" audit "${cargo_audit_ignores[@]}"
{
cd programs/bpf
_ "$cargo" stable audit
for project in rust/*/ ; do
echo "+++ do_bpf_checks $project"
(
cd "$project"
_ "$cargo" nightly clippy -- --deny=warnings --allow=clippy::missing_safety_doc
_ "$cargo" stable fmt -- --check
_ "$cargo" nightly test
_ "$cargo" nightly clippy -- --deny=warnings --allow=clippy::missing_safety_doc
)
done
}

View File

@@ -25,6 +25,9 @@ source scripts/ulimit-n.sh
test -d target/debug/bpf && find target/debug/bpf -name '*.d' -delete
test -d target/release/bpf && find target/release/bpf -name '*.d' -delete
# Clear the BPF sysroot files, they are not automatically rebuilt
rm -rf target/xargo # Issue #3105
# Limit compiler jobs to reduce memory usage
# on machines with 2gb/thread of memory
NPROC=$(nproc)

View File

@@ -1,21 +1,20 @@
[package]
name = "solana-clap-utils"
version = "1.6.3"
version = "1.5.7"
description = "Solana utilities for the clap"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-clap-utils"
edition = "2018"
[dependencies]
clap = "2.33.0"
rpassword = "4.0"
solana-remote-wallet = { path = "../remote-wallet", version = "=1.6.3" }
solana-sdk = { path = "../sdk", version = "=1.6.3" }
solana-remote-wallet = { path = "../remote-wallet", version = "1.5.7" }
solana-sdk = { path = "../sdk", version = "1.5.7" }
thiserror = "1.0.21"
tiny-bip39 = "0.8.0"
tiny-bip39 = "0.7.0"
url = "2.1.0"
chrono = "0.4"

View File

@@ -3,7 +3,7 @@ use chrono::DateTime;
use solana_sdk::{
clock::{Epoch, Slot},
hash::Hash,
pubkey::{Pubkey, MAX_SEED_LEN},
pubkey::Pubkey,
signature::{read_keypair_file, Signature},
};
use std::fmt::Display;
@@ -291,21 +291,6 @@ where
.map(|_| ())
}
pub fn is_derived_address_seed<T>(value: T) -> Result<(), String>
where
T: AsRef<str> + Display,
{
let value = value.as_ref();
if value.len() > MAX_SEED_LEN {
Err(format!(
"Address seed must not be longer than {} bytes",
MAX_SEED_LEN
))
} else {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@@ -12,7 +12,6 @@ use solana_remote_wallet::{
};
use solana_sdk::{
hash::Hash,
message::Message,
pubkey::Pubkey,
signature::{
keypair_from_seed, keypair_from_seed_phrase_and_passphrase, read_keypair,
@@ -29,7 +28,6 @@ use std::{
pub struct SignOnly {
pub blockhash: Hash,
pub message: Option<String>,
pub present_signers: Vec<(Pubkey, Signature)>,
pub absent_signers: Vec<Pubkey>,
pub bad_signers: Vec<Pubkey>,
@@ -69,18 +67,6 @@ impl CliSignerInfo {
None
}
}
pub fn signers_for_message(&self, message: &Message) -> Vec<&dyn Signer> {
self.signers
.iter()
.filter_map(|k| {
if message.signer_keys().contains(&&k.pubkey()) {
Some(k.as_ref())
} else {
None
}
})
.collect()
}
}
pub struct DefaultSigner {
@@ -122,15 +108,6 @@ impl DefaultSigner {
) -> Result<Box<dyn Signer>, Box<dyn std::error::Error>> {
signer_from_path(matches, &self.path, &self.arg_name, wallet_manager)
}
pub fn signer_from_path_with_config(
&self,
matches: &ArgMatches,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
config: &SignerFromPathConfig,
) -> Result<Box<dyn Signer>, Box<dyn std::error::Error>> {
signer_from_path_with_config(matches, &self.path, &self.arg_name, wallet_manager, config)
}
}
pub enum KeypairUrl {
@@ -168,35 +145,11 @@ pub fn presigner_from_pubkey_sigs(
})
}
#[derive(Debug)]
pub struct SignerFromPathConfig {
pub allow_null_signer: bool,
}
impl Default for SignerFromPathConfig {
fn default() -> Self {
Self {
allow_null_signer: false,
}
}
}
pub fn signer_from_path(
matches: &ArgMatches,
path: &str,
keypair_name: &str,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<Box<dyn Signer>, Box<dyn error::Error>> {
let config = SignerFromPathConfig::default();
signer_from_path_with_config(matches, path, keypair_name, wallet_manager, &config)
}
pub fn signer_from_path_with_config(
matches: &ArgMatches,
path: &str,
keypair_name: &str,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
config: &SignerFromPathConfig,
) -> Result<Box<dyn Signer>, Box<dyn error::Error>> {
match parse_keypair_path(path) {
KeypairUrl::Ask => {
@@ -240,7 +193,7 @@ pub fn signer_from_path_with_config(
.and_then(|presigners| presigner_from_pubkey_sigs(&pubkey, presigners));
if let Some(presigner) = presigner {
Ok(Box::new(presigner))
} else if config.allow_null_signer || matches.is_present(SIGN_ONLY_ARG.name) {
} else if matches.is_present(SIGN_ONLY_ARG.name) {
Ok(Box::new(NullSigner::new(&pubkey)))
} else {
Err(std::io::Error::new(
@@ -402,7 +355,6 @@ fn sanitize_seed_phrase(seed_phrase: &str) -> String {
#[cfg(test)]
mod tests {
use super::*;
use solana_sdk::system_instruction;
#[test]
fn test_sanitize_seed_phrase() {
@@ -412,35 +364,4 @@ mod tests {
sanitize_seed_phrase(seed_phrase)
);
}
#[test]
fn test_signer_info_signers_for_message() {
let source = Keypair::new();
let fee_payer = Keypair::new();
let nonsigner1 = Keypair::new();
let nonsigner2 = Keypair::new();
let recipient = Pubkey::new_unique();
let message = Message::new(
&[system_instruction::transfer(
&source.pubkey(),
&recipient,
42,
)],
Some(&fee_payer.pubkey()),
);
let signers = vec![
Box::new(fee_payer) as Box<dyn Signer>,
Box::new(source) as Box<dyn Signer>,
Box::new(nonsigner1) as Box<dyn Signer>,
Box::new(nonsigner2) as Box<dyn Signer>,
];
let signer_info = CliSignerInfo { signers };
let msg_signers = signer_info.signers_for_message(&message);
let signer_pubkeys = msg_signers.iter().map(|s| s.pubkey()).collect::<Vec<_>>();
let expect = vec![
signer_info.signers[0].pubkey(),
signer_info.signers[1].pubkey(),
];
assert_eq!(signer_pubkeys, expect);
}
}

View File

@@ -19,12 +19,6 @@ pub const SIGNER_ARG: ArgConstant<'static> = ArgConstant {
help: "Provide a public-key/signature pair for the transaction",
};
pub const DUMP_TRANSACTION_MESSAGE: ArgConstant<'static> = ArgConstant {
name: "dump_transaction_message",
long: "dump-transaction-message",
help: "Display the base64 encoded binary transaction message in sign-only mode",
};
pub fn blockhash_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(BLOCKHASH_ARG.name)
.long(BLOCKHASH_ARG.long)
@@ -53,14 +47,6 @@ fn signer_arg<'a, 'b>() -> Arg<'a, 'b> {
.help(SIGNER_ARG.help)
}
pub fn dump_transaction_message<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(DUMP_TRANSACTION_MESSAGE.name)
.long(DUMP_TRANSACTION_MESSAGE.long)
.takes_value(false)
.requires(SIGN_ONLY_ARG.name)
.help(DUMP_TRANSACTION_MESSAGE.help)
}
pub trait ArgsConfig {
fn blockhash_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> {
arg
@@ -71,9 +57,6 @@ pub trait ArgsConfig {
fn signer_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> {
arg
}
fn dump_transaction_message_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> {
arg
}
}
pub trait OfflineArgs {
@@ -86,7 +69,6 @@ impl OfflineArgs for App<'_, '_> {
self.arg(config.blockhash_arg(blockhash_arg()))
.arg(config.sign_only_arg(sign_only_arg()))
.arg(config.signer_arg(signer_arg()))
.arg(config.dump_transaction_message_arg(dump_transaction_message()))
}
fn offline_args(self) -> Self {
struct NullArgsConfig {}

View File

@@ -3,16 +3,15 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-cli-config"
description = "Blockchain, Rebuilt for Scale"
version = "1.6.3"
version = "1.5.7"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-cli-config"
[dependencies]
dirs-next = "2.0.0"
lazy_static = "1.4.0"
serde = "1.0.122"
serde = "1.0.112"
serde_derive = "1.0.103"
serde_yaml = "0.8.13"
url = "2.1.1"

View File

@@ -75,8 +75,7 @@ impl Config {
.set_scheme(if is_secure { "wss" } else { "ws" })
.expect("unable to set scheme");
if let Some(port) = json_rpc_url.port() {
let port = port.checked_add(1).expect("port out of range");
ws_url.set_port(Some(port)).expect("unable to set port");
ws_url.set_port(Some(port + 1)).expect("unable to set port");
}
ws_url.to_string()
}

View File

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

View File

@@ -2,12 +2,10 @@ use {
crate::{
display::{
build_balance_message, build_balance_message_with_config, format_labeled_address,
unix_timestamp_to_string, writeln_name_value, writeln_transaction,
BuildBalanceMessageConfig,
unix_timestamp_to_string, writeln_name_value, BuildBalanceMessageConfig,
},
QuietDisplay, VerboseDisplay,
},
chrono::{Local, TimeZone},
console::{style, Emoji},
inflector::cases::titlecase::to_title_case,
serde::{Deserialize, Serialize},
@@ -19,23 +17,19 @@ use {
RpcVoteAccountInfo,
},
solana_sdk::{
clock::{Epoch, Slot, UnixTimestamp},
clock::{self, Epoch, Slot, UnixTimestamp},
epoch_info::EpochInfo,
hash::Hash,
native_token::lamports_to_sol,
pubkey::Pubkey,
signature::Signature,
stake_history::StakeHistoryEntry,
transaction::{Transaction, TransactionError},
transaction::Transaction,
},
solana_stake_program::stake_state::{Authorized, Lockup},
solana_transaction_status::{
EncodedConfirmedBlock, EncodedTransaction, TransactionConfirmationStatus,
UiTransactionStatusMeta,
},
solana_vote_program::{
authorized_voters::AuthorizedVoters,
vote_state::{BlockTimestamp, Lockout, MAX_EPOCH_CREDITS_HISTORY, MAX_LOCKOUT_HISTORY},
vote_state::{BlockTimestamp, Lockout},
},
std::{
collections::{BTreeMap, HashMap},
@@ -231,8 +225,12 @@ pub struct CliSlotStatus {
pub struct CliEpochInfo {
#[serde(flatten)]
pub epoch_info: EpochInfo,
#[serde(skip)]
pub average_slot_time_ms: u64,
}
impl From<EpochInfo> for CliEpochInfo {
fn from(epoch_info: EpochInfo) -> Self {
Self { epoch_info }
}
}
impl QuietDisplay for CliEpochInfo {}
@@ -282,16 +280,19 @@ impl fmt::Display for CliEpochInfo {
"Epoch Completed Time:",
&format!(
"{}/{} ({} remaining)",
slot_to_human_time(self.epoch_info.slot_index, self.average_slot_time_ms),
slot_to_human_time(self.epoch_info.slots_in_epoch, self.average_slot_time_ms),
slot_to_human_time(remaining_slots_in_epoch, self.average_slot_time_ms)
slot_to_human_time(self.epoch_info.slot_index),
slot_to_human_time(self.epoch_info.slots_in_epoch),
slot_to_human_time(remaining_slots_in_epoch)
),
)
}
}
fn slot_to_human_time(slot: Slot, slot_time_ms: u64) -> String {
humantime::format_duration(Duration::from_secs((slot * slot_time_ms) / 1000)).to_string()
fn slot_to_human_time(slot: Slot) -> String {
humantime::format_duration(Duration::from_secs(
slot * clock::DEFAULT_TICKS_PER_SLOT / clock::DEFAULT_TICKS_PER_SECOND,
))
.to_string()
}
#[derive(Serialize, Deserialize, Default)]
@@ -612,55 +613,17 @@ fn show_votes_and_credits(
return Ok(());
}
// Existence of this should guarantee the occurrence of vote truncation
let newest_history_entry = epoch_voting_history.iter().rev().next();
writeln!(f, "Recent Votes:")?;
for vote in votes {
writeln!(f, "- slot: {}", vote.slot)?;
writeln!(f, " confirmation count: {}", vote.confirmation_count)?;
}
writeln!(f, "Epoch Voting History:")?;
writeln!(
f,
"{} Votes (using {}/{} entries):",
(if newest_history_entry.is_none() {
"All"
} else {
"Recent"
}),
votes.len(),
MAX_LOCKOUT_HISTORY
"* missed credits include slots unavailable to vote on due to delinquent leaders",
)?;
for vote in votes.iter().rev() {
writeln!(
f,
"- slot: {} (confirmation count: {})",
vote.slot, vote.confirmation_count
)?;
}
if let Some(newest) = newest_history_entry {
writeln!(
f,
"- ... (truncated {} rooted votes, which have been credited)",
newest.credits
)?;
}
if !epoch_voting_history.is_empty() {
writeln!(
f,
"{} Epoch Voting History (using {}/{} entries):",
(if epoch_voting_history.len() < MAX_EPOCH_CREDITS_HISTORY {
"All"
} else {
"Recent"
}),
epoch_voting_history.len(),
MAX_EPOCH_CREDITS_HISTORY
)?;
writeln!(
f,
"* missed credits include slots unavailable to vote on due to delinquent leaders",
)?;
}
for entry in epoch_voting_history.iter().rev() {
for entry in epoch_voting_history {
writeln!(
f, // tame fmt so that this will be folded like following
"- epoch: {}",
@@ -668,7 +631,7 @@ fn show_votes_and_credits(
)?;
writeln!(
f,
" credits range: ({}..{}]",
" credits range: [{}..{})",
entry.prev_credits, entry.credits
)?;
writeln!(
@@ -677,22 +640,6 @@ fn show_votes_and_credits(
entry.credits_earned, entry.slots_in_epoch
)?;
}
if let Some(oldest) = epoch_voting_history.iter().next() {
if oldest.prev_credits > 0 {
// Oldest entry doesn't start with 0. so history must be truncated...
// count of this combined pseudo credits range: (0..=oldest.prev_credits] like the above
// (or this is just [1..=oldest.prev_credits] for human's simpler minds)
let count = oldest.prev_credits;
writeln!(
f,
"- ... (omitting {} past rooted votes, which have already been credited)",
count
)?;
}
}
Ok(())
}
@@ -1319,8 +1266,6 @@ impl fmt::Display for CliInflation {
#[serde(rename_all = "camelCase")]
pub struct CliSignOnlyData {
pub blockhash: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub message: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub signers: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
@@ -1336,9 +1281,6 @@ impl fmt::Display for CliSignOnlyData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
writeln_name_value(f, "Blockhash:", &self.blockhash)?;
if let Some(message) = self.message.as_ref() {
writeln_name_value(f, "Transaction Message:", message)?;
}
if !self.signers.is_empty() {
writeln!(f, "{}", style("Signers (Pubkey=Signature):").bold())?;
for signer in self.signers.iter() {
@@ -1392,7 +1334,7 @@ impl fmt::Display for CliAccountBalances {
writeln!(
f,
"{}",
style(format!("{:<44} {}", "Address", "Balance")).bold()
style(format!("{:<44} {}", "Address", "Balance",)).bold()
)?;
for account in &self.accounts {
writeln!(
@@ -1458,37 +1400,11 @@ impl fmt::Display for CliSupply {
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliFeesInner {
pub struct CliFees {
pub slot: Slot,
pub blockhash: String,
pub lamports_per_signature: u64,
pub last_valid_slot: Option<Slot>,
}
impl QuietDisplay for CliFeesInner {}
impl VerboseDisplay for CliFeesInner {}
impl fmt::Display for CliFeesInner {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln_name_value(f, "Blockhash:", &self.blockhash)?;
writeln_name_value(
f,
"Lamports per signature:",
&self.lamports_per_signature.to_string(),
)?;
let last_valid_slot = self
.last_valid_slot
.map(|s| s.to_string())
.unwrap_or_default();
writeln_name_value(f, "Last valid slot:", &last_valid_slot)
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliFees {
#[serde(flatten, skip_serializing_if = "Option::is_none")]
pub inner: Option<CliFeesInner>,
pub last_valid_slot: Slot,
}
impl QuietDisplay for CliFees {}
@@ -1496,31 +1412,14 @@ impl VerboseDisplay for CliFees {}
impl fmt::Display for CliFees {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.inner.as_ref() {
Some(inner) => write!(f, "{}", inner),
None => write!(f, "Fees unavailable"),
}
}
}
impl CliFees {
pub fn some(
slot: Slot,
blockhash: Hash,
lamports_per_signature: u64,
last_valid_slot: Option<Slot>,
) -> Self {
Self {
inner: Some(CliFeesInner {
slot,
blockhash: blockhash.to_string(),
lamports_per_signature,
last_valid_slot,
}),
}
}
pub fn none() -> Self {
Self { inner: None }
writeln_name_value(f, "Blockhash:", &self.blockhash)?;
writeln_name_value(
f,
"Lamports per signature:",
&self.lamports_per_signature.to_string(),
)?;
writeln_name_value(f, "Last valid slot:", &self.last_valid_slot.to_string())?;
Ok(())
}
}
@@ -1622,34 +1521,10 @@ impl fmt::Display for CliProgramAuthority {
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliProgram {
pub program_id: String,
pub owner: String,
pub data_len: usize,
}
impl QuietDisplay for CliProgram {}
impl VerboseDisplay for CliProgram {}
impl fmt::Display for CliProgram {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
writeln_name_value(f, "Program Id:", &self.program_id)?;
writeln_name_value(f, "Owner:", &self.owner)?;
writeln_name_value(
f,
"Data Length:",
&format!("{:?} ({:#x?}) bytes", self.data_len, self.data_len),
)?;
Ok(())
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliUpgradeableProgram {
pub program_id: String,
pub owner: String,
pub programdata_address: String,
pub authority: String,
pub last_deploy_slot: u64,
@@ -1661,7 +1536,6 @@ impl fmt::Display for CliUpgradeableProgram {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
writeln_name_value(f, "Program Id:", &self.program_id)?;
writeln_name_value(f, "Owner:", &self.owner)?;
writeln_name_value(f, "ProgramData Address:", &self.programdata_address)?;
writeln_name_value(f, "Authority:", &self.authority)?;
writeln_name_value(
@@ -1684,9 +1558,6 @@ pub struct CliUpgradeableBuffer {
pub address: String,
pub authority: String,
pub data_len: usize,
pub lamports: u64,
#[serde(skip_serializing)]
pub use_lamports_unit: bool,
}
impl QuietDisplay for CliUpgradeableBuffer {}
impl VerboseDisplay for CliUpgradeableBuffer {}
@@ -1695,74 +1566,18 @@ impl fmt::Display for CliUpgradeableBuffer {
writeln!(f)?;
writeln_name_value(f, "Buffer Address:", &self.address)?;
writeln_name_value(f, "Authority:", &self.authority)?;
writeln_name_value(
f,
"Balance:",
&build_balance_message(self.lamports, self.use_lamports_unit, true),
)?;
writeln_name_value(
f,
"Data Length:",
&format!("{:?} ({:#x?}) bytes", self.data_len, self.data_len),
)?;
Ok(())
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliUpgradeableBuffers {
pub buffers: Vec<CliUpgradeableBuffer>,
#[serde(skip_serializing)]
pub use_lamports_unit: bool,
}
impl QuietDisplay for CliUpgradeableBuffers {}
impl VerboseDisplay for CliUpgradeableBuffers {}
impl fmt::Display for CliUpgradeableBuffers {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
writeln!(
f,
"{}",
style(format!(
"{:<44} | {:<44} | {}",
"Buffer Address", "Authority", "Balance"
))
.bold()
)?;
for buffer in self.buffers.iter() {
writeln!(
f,
"{}",
&format!(
"{:<44} | {:<44} | {}",
buffer.address,
buffer.authority,
build_balance_message(buffer.lamports, self.use_lamports_unit, true)
)
)?;
}
Ok(())
}
}
#[derive(Debug, Default)]
pub struct ReturnSignersConfig {
pub dump_transaction_message: bool,
}
pub fn return_signers(
tx: &Transaction,
output_format: &OutputFormat,
) -> Result<String, Box<dyn std::error::Error>> {
return_signers_with_config(tx, output_format, &ReturnSignersConfig::default())
}
pub fn return_signers_with_config(
tx: &Transaction,
output_format: &OutputFormat,
config: &ReturnSignersConfig,
) -> Result<String, Box<dyn std::error::Error>> {
let verify_results = tx.verify_with_results();
let mut signers = Vec::new();
@@ -1781,16 +1596,9 @@ pub fn return_signers_with_config(
bad_sig.push(key.to_string());
}
});
let message = if config.dump_transaction_message {
let message_data = tx.message_data();
Some(base64::encode(&message_data))
} else {
None
};
let cli_command = CliSignOnlyData {
blockhash: tx.message.recent_blockhash.to_string(),
message,
signers,
absent,
bad_sig,
@@ -1845,22 +1653,15 @@ pub fn parse_sign_only_reply_string(reply: &str) -> SignOnly {
.collect();
}
let message = object
.get("message")
.and_then(|o| o.as_str())
.map(|m| m.to_string());
SignOnly {
blockhash,
message,
present_signers,
absent_signers,
bad_signers,
}
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[derive(Debug)]
pub enum CliSignatureVerificationStatus {
None,
Pass,
@@ -1891,192 +1692,6 @@ impl fmt::Display for CliSignatureVerificationStatus {
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliBlock {
#[serde(flatten)]
pub encoded_confirmed_block: EncodedConfirmedBlock,
#[serde(skip_serializing)]
pub slot: Slot,
}
impl QuietDisplay for CliBlock {}
impl VerboseDisplay for CliBlock {}
impl fmt::Display for CliBlock {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "Slot: {}", self.slot)?;
writeln!(
f,
"Parent Slot: {}",
self.encoded_confirmed_block.parent_slot
)?;
writeln!(f, "Blockhash: {}", self.encoded_confirmed_block.blockhash)?;
writeln!(
f,
"Previous Blockhash: {}",
self.encoded_confirmed_block.previous_blockhash
)?;
if let Some(block_time) = self.encoded_confirmed_block.block_time {
writeln!(f, "Block Time: {:?}", Local.timestamp(block_time, 0))?;
}
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));
let mut total_rewards = 0;
writeln!(f, "Rewards:")?;
writeln!(
f,
" {:<44} {:^15} {:<15} {:<20} {:>14}",
"Address", "Type", "Amount", "New Balance", "Percent Change"
)?;
for reward in rewards {
let sign = if reward.lamports < 0 { "-" } else { "" };
total_rewards += reward.lamports;
writeln!(
f,
" {:<44} {:^15} {:>15} {}",
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)
),
if reward.post_balance == 0 {
" - -".to_string()
} else {
format!(
"{:<19.9} {:>13.9}%",
lamports_to_sol(reward.post_balance),
(reward.lamports.abs() as f64
/ (reward.post_balance as f64 - reward.lamports as f64))
* 100.0
)
}
)?;
}
let sign = if total_rewards < 0 { "-" } else { "" };
writeln!(
f,
"Total Rewards: {}◎{:<12.9}",
sign,
lamports_to_sol(total_rewards.abs() as u64)
)?;
}
for (index, transaction_with_meta) in
self.encoded_confirmed_block.transactions.iter().enumerate()
{
writeln!(f, "Transaction {}:", index)?;
writeln_transaction(
f,
&transaction_with_meta.transaction.decode().unwrap(),
&transaction_with_meta.meta,
" ",
None,
None,
)?;
}
Ok(())
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliTransaction {
pub transaction: EncodedTransaction,
pub meta: Option<UiTransactionStatusMeta>,
pub block_time: Option<UnixTimestamp>,
#[serde(skip_serializing)]
pub slot: Option<Slot>,
#[serde(skip_serializing)]
pub decoded_transaction: Transaction,
#[serde(skip_serializing)]
pub prefix: String,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub sigverify_status: Vec<CliSignatureVerificationStatus>,
}
impl QuietDisplay for CliTransaction {}
impl VerboseDisplay for CliTransaction {}
impl fmt::Display for CliTransaction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln_transaction(
f,
&self.decoded_transaction,
&self.meta,
&self.prefix,
if !self.sigverify_status.is_empty() {
Some(&self.sigverify_status)
} else {
None
},
self.block_time,
)
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliTransactionConfirmation {
pub confirmation_status: Option<TransactionConfirmationStatus>,
#[serde(flatten, skip_serializing_if = "Option::is_none")]
pub transaction: Option<CliTransaction>,
#[serde(skip_serializing)]
pub get_transaction_error: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub err: Option<TransactionError>,
}
impl QuietDisplay for CliTransactionConfirmation {}
impl VerboseDisplay for CliTransactionConfirmation {
fn write_str(&self, w: &mut dyn std::fmt::Write) -> std::fmt::Result {
if let Some(transaction) = &self.transaction {
writeln!(
w,
"\nTransaction executed in slot {}:",
transaction.slot.expect("slot should exist")
)?;
write!(w, "{}", transaction)?;
} else if let Some(confirmation_status) = &self.confirmation_status {
if confirmation_status != &TransactionConfirmationStatus::Finalized {
writeln!(w)?;
writeln!(
w,
"Unable to get finalized transaction details: not yet finalized"
)?;
} else if let Some(err) = &self.get_transaction_error {
writeln!(w)?;
writeln!(w, "Unable to get finalized transaction details: {}", err)?;
}
}
writeln!(w)?;
write!(w, "{}", self)
}
}
impl fmt::Display for CliTransactionConfirmation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.confirmation_status {
None => write!(f, "Not found"),
Some(confirmation_status) => {
if let Some(err) = &self.err {
write!(f, "Transaction failed: {}", err)
} else {
write!(f, "{:?}", confirmation_status)
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
@@ -2131,25 +1746,6 @@ mod tests {
let res = return_signers(&tx, &OutputFormat::JsonCompact).unwrap();
let sign_only = parse_sign_only_reply_string(&res);
assert_eq!(sign_only.blockhash, blockhash);
assert_eq!(sign_only.message, None);
assert_eq!(sign_only.present_signers[0].0, present.pubkey());
assert_eq!(sign_only.absent_signers[0], absent.pubkey());
assert_eq!(sign_only.bad_signers[0], bad.pubkey());
let expected_msg = "AwECBwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDgTl3Dqh9\
F19Wo1Rmw0x+zMuNipG07jeiXfYPW4/Js5QEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE\
BAQEBAYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBQUFBQUFBQUFBQUFBQUFBQUF\
BQUFBQUFBQUFBQUFBQUGp9UXGSxWjuCKhF9z0peIzwNcMUWyGrNE2AYuqUAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcH\
BwcCBgMDBQIEBAAAAAYCAQQMAgAAACoAAAAAAAAA"
.to_string();
let config = ReturnSignersConfig {
dump_transaction_message: true,
};
let res = return_signers_with_config(&tx, &OutputFormat::JsonCompact, &config).unwrap();
let sign_only = parse_sign_only_reply_string(&res);
assert_eq!(sign_only.blockhash, blockhash);
assert_eq!(sign_only.message, Some(expected_msg));
assert_eq!(sign_only.present_signers[0].0, present.pubkey());
assert_eq!(sign_only.absent_signers[0], absent.pubkey());
assert_eq!(sign_only.bad_signers[0], bad.pubkey());

View File

@@ -1,10 +1,10 @@
use {
crate::cli_output::CliSignatureVerificationStatus,
chrono::{DateTime, Local, NaiveDateTime, SecondsFormat, TimeZone, Utc},
chrono::{DateTime, NaiveDateTime, SecondsFormat, Utc},
console::style,
indicatif::{ProgressBar, ProgressStyle},
solana_sdk::{
clock::UnixTimestamp, hash::Hash, message::Message, native_token::lamports_to_sol,
clock::UnixTimestamp, hash::Hash, native_token::lamports_to_sol,
program_utils::limited_deserialize, transaction::Transaction,
},
solana_transaction_status::UiTransactionStatusMeta,
@@ -125,48 +125,14 @@ pub fn println_signers(
println!();
}
fn format_account_mode(message: &Message, index: usize) -> String {
format!(
"{}r{}{}", // accounts are always readable...
if message.is_signer(index) {
"s" // stands for signer
} else {
"-"
},
if message.is_writable(index, /*demote_sysvar_write_locks=*/ true) {
"w" // comment for consistent rust fmt (no joking; lol)
} else {
"-"
},
// account may be executable on-chain while not being
// designated as a program-id in the message
if message.maybe_executable(index) {
"x"
} else {
// programs to be executed via CPI cannot be identified as
// executable from the message
"-"
},
)
}
pub fn write_transaction<W: io::Write>(
w: &mut W,
transaction: &Transaction,
transaction_status: &Option<UiTransactionStatusMeta>,
prefix: &str,
sigverify_status: Option<&[CliSignatureVerificationStatus]>,
block_time: Option<UnixTimestamp>,
) -> io::Result<()> {
let message = &transaction.message;
if let Some(block_time) = block_time {
writeln!(
w,
"{}Block Time: {:?}",
prefix,
Local.timestamp(block_time, 0)
)?;
}
writeln!(
w,
"{}Recent Blockhash: {:?}",
@@ -192,31 +158,16 @@ pub fn write_transaction<W: io::Write>(
prefix, signature_index, signature, sigverify_status,
)?;
}
let mut fee_payer_index = None;
writeln!(w, "{}{:?}", prefix, message.header)?;
for (account_index, account) in message.account_keys.iter().enumerate() {
if fee_payer_index.is_none() && message.is_non_loader_key(account, account_index) {
fee_payer_index = Some(account_index)
}
writeln!(
w,
"{}Account {}: {} {}{}",
prefix,
account_index,
format_account_mode(message, account_index),
account,
if Some(account_index) == fee_payer_index {
" (fee payer)"
} else {
""
},
)?;
writeln!(w, "{}Account {}: {:?}", prefix, account_index, account)?;
}
for (instruction_index, instruction) in message.instructions.iter().enumerate() {
let program_pubkey = message.account_keys[instruction.program_id_index as usize];
writeln!(w, "{}Instruction {}", prefix, instruction_index)?;
writeln!(
w,
"{} Program: {} ({})",
"{} Program: {} ({})",
prefix, program_pubkey, instruction.program_id_index
)?;
for (account_index, account) in instruction.accounts.iter().enumerate() {
@@ -326,7 +277,6 @@ pub fn println_transaction(
transaction_status: &Option<UiTransactionStatusMeta>,
prefix: &str,
sigverify_status: Option<&[CliSignatureVerificationStatus]>,
block_time: Option<UnixTimestamp>,
) {
let mut w = Vec::new();
if write_transaction(
@@ -335,7 +285,6 @@ pub fn println_transaction(
transaction_status,
prefix,
sigverify_status,
block_time,
)
.is_ok()
{
@@ -345,32 +294,6 @@ pub fn println_transaction(
}
}
pub fn writeln_transaction(
f: &mut dyn fmt::Write,
transaction: &Transaction,
transaction_status: &Option<UiTransactionStatusMeta>,
prefix: &str,
sigverify_status: Option<&[CliSignatureVerificationStatus]>,
block_time: Option<UnixTimestamp>,
) -> fmt::Result {
let mut w = Vec::new();
if write_transaction(
&mut w,
transaction,
transaction_status,
prefix,
sigverify_status,
block_time,
)
.is_ok()
{
if let Ok(s) = String::from_utf8(w) {
write!(f, "{}", s)?;
}
}
Ok(())
}
/// Creates a new process bar for processing that will take an unknown amount of time
pub fn new_spinner_progress_bar() -> ProgressBar {
let progress_bar = ProgressBar::new(42);

View File

@@ -1,4 +1,3 @@
#![allow(clippy::integer_arithmetic)]
mod cli_output;
pub mod display;
pub use cli_output::*;

View File

@@ -3,11 +3,10 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-cli"
description = "Blockchain, Rebuilt for Scale"
version = "1.6.3"
version = "1.5.7"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-cli"
[dependencies]
bincode = "1.3.1"
@@ -24,33 +23,33 @@ indicatif = "0.15.0"
humantime = "2.0.1"
num-traits = "0.2"
pretty-hex = "0.2.1"
reqwest = { version = "0.11.2", default-features = false, features = ["blocking", "rustls-tls", "json"] }
serde = "1.0.122"
reqwest = { version = "0.10.8", default-features = false, features = ["blocking", "rustls-tls", "json"] }
serde = "1.0.112"
serde_derive = "1.0.103"
serde_json = "1.0.56"
solana-account-decoder = { path = "../account-decoder", version = "=1.6.3" }
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "=1.6.3" }
solana-clap-utils = { path = "../clap-utils", version = "=1.6.3" }
solana-cli-config = { path = "../cli-config", version = "=1.6.3" }
solana-cli-output = { path = "../cli-output", version = "=1.6.3" }
solana-client = { path = "../client", version = "=1.6.3" }
solana-config-program = { path = "../programs/config", version = "=1.6.3" }
solana-faucet = { path = "../faucet", version = "=1.6.3" }
solana-logger = { path = "../logger", version = "=1.6.3" }
solana-net-utils = { path = "../net-utils", version = "=1.6.3" }
solana_rbpf = "=0.2.5"
solana-remote-wallet = { path = "../remote-wallet", version = "=1.6.3" }
solana-sdk = { path = "../sdk", version = "=1.6.3" }
solana-stake-program = { path = "../programs/stake", version = "=1.6.3" }
solana-transaction-status = { path = "../transaction-status", version = "=1.6.3" }
solana-version = { path = "../version", version = "=1.6.3" }
solana-vote-program = { path = "../programs/vote", version = "=1.6.3" }
solana-account-decoder = { path = "../account-decoder", version = "1.5.7" }
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.5.7" }
solana-clap-utils = { path = "../clap-utils", version = "1.5.7" }
solana-cli-config = { path = "../cli-config", version = "1.5.7" }
solana-cli-output = { path = "../cli-output", version = "1.5.7" }
solana-client = { path = "../client", version = "1.5.7" }
solana-config-program = { path = "../programs/config", version = "1.5.7" }
solana-faucet = { path = "../faucet", version = "1.5.7" }
solana-logger = { path = "../logger", version = "1.5.7" }
solana-net-utils = { path = "../net-utils", version = "1.5.7" }
solana_rbpf = "=0.2.4"
solana-remote-wallet = { path = "../remote-wallet", version = "1.5.7" }
solana-sdk = { path = "../sdk", version = "1.5.7" }
solana-stake-program = { path = "../programs/stake", version = "1.5.7" }
solana-transaction-status = { path = "../transaction-status", version = "1.5.7" }
solana-version = { path = "../version", version = "1.5.7" }
solana-vote-program = { path = "../programs/vote", version = "1.5.7" }
thiserror = "1.0.21"
tiny-bip39 = "0.7.0"
url = "2.1.1"
[dev-dependencies]
solana-core = { path = "../core", version = "=1.6.3" }
solana-core = { path = "../core", version = "1.5.7" }
tempfile = "3.1.0"
[[bin]]

View File

@@ -86,13 +86,9 @@ pub fn check_account_for_spend_multiple_fees_with_commitment(
return Err(CliError::InsufficientFundsForSpendAndFee(
lamports_to_sol(balance),
lamports_to_sol(fee),
*account_pubkey,
));
} else {
return Err(CliError::InsufficientFundsForFee(
lamports_to_sol(fee),
*account_pubkey,
));
return Err(CliError::InsufficientFundsForFee(lamports_to_sol(fee)));
}
}
Ok(())

View File

@@ -17,19 +17,15 @@ use solana_clap_utils::{
offline::*,
};
use solana_cli_output::{
display::{build_balance_message, println_name_value},
return_signers_with_config, CliAccount, CliSignature, CliSignatureVerificationStatus,
CliTransaction, CliTransactionConfirmation, OutputFormat, ReturnSignersConfig,
display::{build_balance_message, println_name_value, println_transaction},
return_signers, CliAccount, CliSignature, CliSignatureVerificationStatus, OutputFormat,
};
use solana_client::{
blockhash_query::BlockhashQuery,
client_error::{ClientError, ClientErrorKind, Result as ClientResult},
nonce_utils,
rpc_client::RpcClient,
rpc_config::{
RpcConfirmedTransactionConfig, RpcLargestAccountsFilter, RpcSendTransactionConfig,
RpcTransactionLogsFilter,
},
rpc_config::{RpcLargestAccountsFilter, RpcSendTransactionConfig, RpcTransactionLogsFilter},
rpc_response::RpcKeyedAccount,
};
#[cfg(not(test))]
@@ -44,7 +40,7 @@ use solana_sdk::{
hash::Hash,
instruction::InstructionError,
message::Message,
pubkey::Pubkey,
pubkey::{Pubkey, MAX_SEED_LEN},
signature::{Signature, Signer, SignerError},
system_instruction::{self, SystemError},
system_program,
@@ -54,7 +50,9 @@ use solana_stake_program::{
stake_instruction::LockupArgs,
stake_state::{Lockup, StakeAuthorize},
};
use solana_transaction_status::{EncodedTransaction, UiTransactionEncoding};
use solana_transaction_status::{
EncodedTransaction, TransactionConfirmationStatus, UiTransactionEncoding,
};
use solana_vote_program::vote_state::VoteAuthorize;
use std::{
collections::HashMap,
@@ -93,9 +91,7 @@ pub enum CliCommand {
},
Feature(FeatureCliCommand),
Inflation(InflationCliCommand),
Fees {
blockhash: Option<Hash>,
},
Fees,
FirstAvailableBlock,
GetBlock {
slot: Option<Slot>,
@@ -201,7 +197,6 @@ pub enum CliCommand {
lockup: Lockup,
amount: SpendAmount,
sign_only: bool,
dump_transaction_message: bool,
blockhash_query: BlockhashQuery,
nonce_account: Option<Pubkey>,
nonce_authority: SignerIndex,
@@ -212,7 +207,6 @@ pub enum CliCommand {
stake_account_pubkey: Pubkey,
stake_authority: SignerIndex,
sign_only: bool,
dump_transaction_message: bool,
blockhash_query: BlockhashQuery,
nonce_account: Option<Pubkey>,
nonce_authority: SignerIndex,
@@ -224,7 +218,6 @@ pub enum CliCommand {
stake_authority: SignerIndex,
force: bool,
sign_only: bool,
dump_transaction_message: bool,
blockhash_query: BlockhashQuery,
nonce_account: Option<Pubkey>,
nonce_authority: SignerIndex,
@@ -234,7 +227,6 @@ pub enum CliCommand {
stake_account_pubkey: Pubkey,
stake_authority: SignerIndex,
sign_only: bool,
dump_transaction_message: bool,
blockhash_query: BlockhashQuery,
nonce_account: Option<Pubkey>,
nonce_authority: SignerIndex,
@@ -248,7 +240,6 @@ pub enum CliCommand {
source_stake_account_pubkey: Pubkey,
stake_authority: SignerIndex,
sign_only: bool,
dump_transaction_message: bool,
blockhash_query: BlockhashQuery,
nonce_account: Option<Pubkey>,
nonce_authority: SignerIndex,
@@ -265,7 +256,6 @@ pub enum CliCommand {
stake_account_pubkey: Pubkey,
new_authorizations: Vec<(StakeAuthorize, Pubkey, SignerIndex)>,
sign_only: bool,
dump_transaction_message: bool,
blockhash_query: BlockhashQuery,
nonce_account: Option<Pubkey>,
nonce_authority: SignerIndex,
@@ -277,7 +267,6 @@ pub enum CliCommand {
lockup: LockupArgs,
custodian: SignerIndex,
sign_only: bool,
dump_transaction_message: bool,
blockhash_query: BlockhashQuery,
nonce_account: Option<Pubkey>,
nonce_authority: SignerIndex,
@@ -290,7 +279,6 @@ pub enum CliCommand {
withdraw_authority: SignerIndex,
custodian: Option<SignerIndex>,
sign_only: bool,
dump_transaction_message: bool,
blockhash_query: BlockhashQuery,
nonce_account: Option<Pubkey>,
nonce_authority: SignerIndex,
@@ -362,15 +350,11 @@ pub enum CliCommand {
to: Pubkey,
from: SignerIndex,
sign_only: bool,
dump_transaction_message: bool,
allow_unfunded_recipient: bool,
no_wait: bool,
blockhash_query: BlockhashQuery,
nonce_account: Option<Pubkey>,
nonce_authority: SignerIndex,
fee_payer: SignerIndex,
derived_address_seed: Option<String>,
derived_address_program_id: Option<Pubkey>,
},
}
@@ -382,25 +366,25 @@ pub struct CliCommandInfo {
#[derive(Debug, Error)]
pub enum CliError {
#[error("Bad parameter: {0}")]
#[error("bad parameter: {0}")]
BadParameter(String),
#[error(transparent)]
ClientError(#[from] ClientError),
#[error("Command not recognized: {0}")]
#[error("command not recognized: {0}")]
CommandNotRecognized(String),
#[error("Account {1} has insufficient funds for fee ({0} SOL)")]
InsufficientFundsForFee(f64, Pubkey),
#[error("Account {1} has insufficient funds for spend ({0} SOL)")]
InsufficientFundsForSpend(f64, Pubkey),
#[error("Account {2} has insufficient funds for spend ({0} SOL) + fee ({1} SOL)")]
InsufficientFundsForSpendAndFee(f64, f64, Pubkey),
#[error("insufficient funds for fee ({0} SOL)")]
InsufficientFundsForFee(f64),
#[error("insufficient funds for spend ({0} SOL)")]
InsufficientFundsForSpend(f64),
#[error("insufficient funds for spend ({0} SOL) and fee ({1} SOL)")]
InsufficientFundsForSpendAndFee(f64, f64),
#[error(transparent)]
InvalidNonce(nonce_utils::Error),
#[error("Dynamic program error: {0}")]
#[error("dynamic program error: {0}")]
DynamicProgramError(String),
#[error("RPC request error: {0}")]
#[error("rpc request error: {0}")]
RpcRequestError(String),
#[error("Keypair file not found: {0}")]
#[error("keypair file not found: {0}")]
KeypairFileNotFound(String),
}
@@ -608,13 +592,10 @@ pub fn parse_command(
("feature", Some(matches)) => {
parse_feature_subcommand(matches, default_signer, wallet_manager)
}
("fees", Some(matches)) => {
let blockhash = value_of::<Hash>(matches, "blockhash");
Ok(CliCommandInfo {
command: CliCommand::Fees { blockhash },
signers: vec![],
})
}
("fees", Some(_matches)) => Ok(CliCommandInfo {
command: CliCommand::Fees,
signers: vec![],
}),
("first-available-block", Some(_matches)) => Ok(CliCommandInfo {
command: CliCommand::FirstAvailableBlock,
signers: vec![],
@@ -860,7 +841,6 @@ pub fn parse_command(
let amount = SpendAmount::new_from_matches(matches, "amount");
let to = pubkey_of_signer(matches, "to", wallet_manager)?.unwrap();
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name);
let no_wait = matches.is_present("no_wait");
let blockhash_query = BlockhashQuery::new_from_matches(matches);
let nonce_account = pubkey_of_signer(matches, NONCE_ARG.name, wallet_manager)?;
@@ -869,7 +849,6 @@ pub fn parse_command(
let (fee_payer, fee_payer_pubkey) =
signer_of(matches, FEE_PAYER_ARG.name, wallet_manager)?;
let (from, from_pubkey) = signer_of(matches, "from", wallet_manager)?;
let allow_unfunded_recipient = matches.is_present("allow_unfunded_recipient");
let mut bulk_signers = vec![fee_payer, from];
if nonce_account.is_some() {
@@ -879,27 +858,17 @@ pub fn parse_command(
let signer_info =
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
let derived_address_seed = matches
.value_of("derived_address_seed")
.map(|s| s.to_string());
let derived_address_program_id =
resolve_derived_address_program_id(matches, "derived_address_program_id");
Ok(CliCommandInfo {
command: CliCommand::Transfer {
amount,
to,
sign_only,
dump_transaction_message,
allow_unfunded_recipient,
no_wait,
blockhash_query,
nonce_account,
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
from: signer_info.index_of(from_pubkey).unwrap(),
derived_address_seed,
derived_address_program_id,
},
signers: signer_info.signers,
})
@@ -929,15 +898,6 @@ pub fn parse_command(
pub type ProcessResult = Result<String, Box<dyn std::error::Error>>;
fn resolve_derived_address_program_id(matches: &ArgMatches<'_>, arg_name: &str) -> Option<Pubkey> {
matches.value_of(arg_name).and_then(|v| match v {
"NONCE" => Some(system_program::id()),
"STAKE" => Some(solana_stake_program::id()),
"VOTE" => Some(solana_vote_program::id()),
_ => pubkey_of(matches, arg_name),
})
}
pub fn parse_create_address_with_seed(
matches: &ArgMatches<'_>,
default_signer: &DefaultSigner,
@@ -950,10 +910,21 @@ pub fn parse_create_address_with_seed(
vec![default_signer.signer_from_path(matches, wallet_manager)?]
};
let program_id = resolve_derived_address_program_id(matches, "program_id").unwrap();
let program_id = match matches.value_of("program_id").unwrap() {
"NONCE" => system_program::id(),
"STAKE" => solana_stake_program::id(),
"VOTE" => solana_vote_program::id(),
_ => pubkey_of(matches, "program_id").unwrap(),
};
let seed = matches.value_of("seed").unwrap().to_string();
if seed.len() > MAX_SEED_LEN {
return Err(CliError::BadParameter(
"Address seed must not be longer than 32 bytes".to_string(),
));
}
Ok(CliCommandInfo {
command: CliCommand::CreateAddressWithSeed {
from_pubkey,
@@ -1026,76 +997,60 @@ fn process_confirm(
) -> ProcessResult {
match rpc_client.get_signature_statuses_with_history(&[*signature]) {
Ok(status) => {
let cli_transaction = if let Some(transaction_status) = &status.value[0] {
let mut transaction = None;
let mut get_transaction_error = None;
if let Some(transaction_status) = &status.value[0] {
if config.verbose {
match rpc_client.get_confirmed_transaction_with_config(
signature,
RpcConfirmedTransactionConfig {
encoding: Some(UiTransactionEncoding::Base64),
commitment: Some(CommitmentConfig::confirmed()),
},
) {
match rpc_client
.get_confirmed_transaction(signature, UiTransactionEncoding::Base64)
{
Ok(confirmed_transaction) => {
let decoded_transaction = confirmed_transaction
.transaction
.transaction
.decode()
.expect("Successful decode");
let json_transaction = EncodedTransaction::encode(
decoded_transaction.clone(),
UiTransactionEncoding::Json,
println!(
"\nTransaction executed in slot {}:",
confirmed_transaction.slot
);
println_transaction(
&confirmed_transaction
.transaction
.transaction
.decode()
.expect("Successful decode"),
&confirmed_transaction.transaction.meta,
" ",
None,
);
transaction = Some(CliTransaction {
transaction: json_transaction,
meta: confirmed_transaction.transaction.meta,
block_time: confirmed_transaction.block_time,
slot: Some(confirmed_transaction.slot),
decoded_transaction,
prefix: " ".to_string(),
sigverify_status: vec![],
});
}
Err(err) => {
get_transaction_error = Some(format!("{:?}", err));
if transaction_status.confirmation_status()
!= TransactionConfirmationStatus::Finalized
{
println!();
println!("Unable to get finalized transaction details: not yet finalized")
} else {
println!();
println!("Unable to get finalized transaction details: {}", err)
}
}
}
println!();
}
CliTransactionConfirmation {
confirmation_status: Some(transaction_status.confirmation_status()),
transaction,
get_transaction_error,
err: transaction_status.err.clone(),
if let Some(err) = &transaction_status.err {
Ok(format!("Transaction failed: {}", err))
} else {
Ok(format!("{:?}", transaction_status.confirmation_status()))
}
} else {
CliTransactionConfirmation {
confirmation_status: None,
transaction: None,
get_transaction_error: None,
err: None,
}
};
Ok(config.output_format.formatted_string(&cli_transaction))
Ok("Not found".to_string())
}
}
Err(err) => Err(CliError::RpcRequestError(format!("Unable to confirm: {}", err)).into()),
}
}
#[allow(clippy::unnecessary_wraps)]
fn process_decode_transaction(config: &CliConfig, transaction: &Transaction) -> ProcessResult {
let sigverify_status = CliSignatureVerificationStatus::verify_transaction(&transaction);
let decode_transaction = CliTransaction {
decoded_transaction: transaction.clone(),
transaction: EncodedTransaction::encode(transaction.clone(), UiTransactionEncoding::Json),
meta: None,
block_time: None,
slot: None,
prefix: "".to_string(),
sigverify_status,
};
Ok(config.output_format.formatted_string(&decode_transaction))
fn process_decode_transaction(transaction: &Transaction) -> ProcessResult {
let sig_stats = CliSignatureVerificationStatus::verify_transaction(&transaction);
println_transaction(transaction, &None, "", Some(&sig_stats));
Ok("".to_string())
}
fn process_show_account(
@@ -1148,62 +1103,22 @@ fn process_transfer(
to: &Pubkey,
from: SignerIndex,
sign_only: bool,
dump_transaction_message: bool,
allow_unfunded_recipient: bool,
no_wait: bool,
blockhash_query: &BlockhashQuery,
nonce_account: Option<&Pubkey>,
nonce_authority: SignerIndex,
fee_payer: SignerIndex,
derived_address_seed: Option<String>,
derived_address_program_id: Option<&Pubkey>,
) -> ProcessResult {
let from = config.signers[from];
let mut from_pubkey = from.pubkey();
let (recent_blockhash, fee_calculator) =
blockhash_query.get_blockhash_and_fee_calculator(rpc_client, config.commitment)?;
if !sign_only && !allow_unfunded_recipient {
let recipient_balance = rpc_client
.get_balance_with_commitment(to, config.commitment)?
.value;
if recipient_balance == 0 {
return Err(format!(
"The recipient address ({}) is not funded. \
Add `--allow-unfunded-recipient` to complete the transfer \
",
to
)
.into());
}
}
let nonce_authority = config.signers[nonce_authority];
let fee_payer = config.signers[fee_payer];
let derived_parts = derived_address_seed.zip(derived_address_program_id);
let with_seed = if let Some((seed, program_id)) = derived_parts {
let base_pubkey = from_pubkey;
from_pubkey = Pubkey::create_with_seed(&base_pubkey, &seed, program_id)?;
Some((base_pubkey, seed, program_id, from_pubkey))
} else {
None
};
let build_message = |lamports| {
let ixs = if let Some((base_pubkey, seed, program_id, from_pubkey)) = with_seed.as_ref() {
vec![system_instruction::transfer_with_seed(
from_pubkey,
base_pubkey,
seed.clone(),
program_id,
to,
lamports,
)]
} else {
vec![system_instruction::transfer(&from_pubkey, to, lamports)]
};
let ixs = vec![system_instruction::transfer(&from.pubkey(), to, lamports)];
if let Some(nonce_account) = &nonce_account {
Message::new_with_nonce(
@@ -1222,7 +1137,7 @@ fn process_transfer(
sign_only,
amount,
&fee_calculator,
&from_pubkey,
&from.pubkey(),
&fee_payer.pubkey(),
build_message,
config.commitment,
@@ -1231,13 +1146,7 @@ fn process_transfer(
if sign_only {
tx.try_partial_sign(&config.signers, recent_blockhash)?;
return_signers_with_config(
&tx,
&config.output_format,
&ReturnSignersConfig {
dump_transaction_message,
},
)
return_signers(&tx, &config.output_format)
} else {
if let Some(nonce_account) = &nonce_account {
let nonce_account = nonce_utils::get_account_with_commitment(
@@ -1312,7 +1221,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
seed,
program_id,
} => process_create_address_with_seed(config, from_pubkey.as_ref(), &seed, &program_id),
CliCommand::Fees { ref blockhash } => process_fees(&rpc_client, config, blockhash.as_ref()),
CliCommand::Fees => process_fees(&rpc_client, config),
CliCommand::Feature(feature_subcommand) => {
process_feature_subcommand(&rpc_client, config, feature_subcommand)
}
@@ -1489,7 +1398,6 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
lockup,
amount,
sign_only,
dump_transaction_message,
blockhash_query,
ref nonce_account,
nonce_authority,
@@ -1505,7 +1413,6 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
lockup,
*amount,
*sign_only,
*dump_transaction_message,
blockhash_query,
nonce_account.as_ref(),
*nonce_authority,
@@ -1516,7 +1423,6 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
stake_account_pubkey,
stake_authority,
sign_only,
dump_transaction_message,
blockhash_query,
nonce_account,
nonce_authority,
@@ -1527,7 +1433,6 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
&stake_account_pubkey,
*stake_authority,
*sign_only,
*dump_transaction_message,
blockhash_query,
*nonce_account,
*nonce_authority,
@@ -1539,7 +1444,6 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
stake_authority,
force,
sign_only,
dump_transaction_message,
blockhash_query,
nonce_account,
nonce_authority,
@@ -1552,7 +1456,6 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
*stake_authority,
*force,
*sign_only,
*dump_transaction_message,
blockhash_query,
*nonce_account,
*nonce_authority,
@@ -1562,7 +1465,6 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
stake_account_pubkey,
stake_authority,
sign_only,
dump_transaction_message,
blockhash_query,
nonce_account,
nonce_authority,
@@ -1576,7 +1478,6 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
&stake_account_pubkey,
*stake_authority,
*sign_only,
*dump_transaction_message,
blockhash_query,
*nonce_account,
*nonce_authority,
@@ -1590,7 +1491,6 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
source_stake_account_pubkey,
stake_authority,
sign_only,
dump_transaction_message,
blockhash_query,
nonce_account,
nonce_authority,
@@ -1602,7 +1502,6 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
&source_stake_account_pubkey,
*stake_authority,
*sign_only,
*dump_transaction_message,
blockhash_query,
*nonce_account,
*nonce_authority,
@@ -1624,7 +1523,6 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
stake_account_pubkey,
ref new_authorizations,
sign_only,
dump_transaction_message,
blockhash_query,
nonce_account,
nonce_authority,
@@ -1637,7 +1535,6 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
new_authorizations,
*custodian,
*sign_only,
*dump_transaction_message,
blockhash_query,
*nonce_account,
*nonce_authority,
@@ -1648,7 +1545,6 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
mut lockup,
custodian,
sign_only,
dump_transaction_message,
blockhash_query,
nonce_account,
nonce_authority,
@@ -1660,7 +1556,6 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
&mut lockup,
*custodian,
*sign_only,
*dump_transaction_message,
blockhash_query,
*nonce_account,
*nonce_authority,
@@ -1673,7 +1568,6 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
withdraw_authority,
custodian,
sign_only,
dump_transaction_message,
blockhash_query,
ref nonce_account,
nonce_authority,
@@ -1687,7 +1581,6 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
*withdraw_authority,
*custodian,
*sign_only,
*dump_transaction_message,
blockhash_query,
nonce_account.as_ref(),
*nonce_authority,
@@ -1821,9 +1714,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
} => process_balance(&rpc_client, config, &pubkey, *use_lamports_unit),
// Confirm the last client transaction by signature
CliCommand::Confirm(signature) => process_confirm(&rpc_client, config, signature),
CliCommand::DecodeTransaction(transaction) => {
process_decode_transaction(config, transaction)
}
CliCommand::DecodeTransaction(transaction) => process_decode_transaction(transaction),
CliCommand::ResolveSigner(path) => {
if let Some(path) = path {
Ok(path.to_string())
@@ -1847,15 +1738,11 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
to,
from,
sign_only,
dump_transaction_message,
allow_unfunded_recipient,
no_wait,
ref blockhash_query,
ref nonce_account,
nonce_authority,
fee_payer,
derived_address_seed,
ref derived_address_program_id,
} => process_transfer(
&rpc_client,
config,
@@ -1863,15 +1750,11 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
to,
*from,
*sign_only,
*dump_transaction_message,
*allow_unfunded_recipient,
*no_wait,
blockhash_query,
nonce_account.as_ref(),
*nonce_authority,
*fee_payer,
derived_address_seed.clone(),
derived_address_program_id.as_ref(),
),
}
}
@@ -2051,17 +1934,6 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
.takes_value(true)
.required(true)
.help("The transaction signature to confirm"),
)
.after_help(// Formatted specifically for the manually-indented heredoc string
"Note: This will show more detailed information for finalized transactions with verbose mode (-v/--verbose).\
\n\
\nAccount modes:\
\n |srwx|\
\n s: signed\
\n r: readable (always true)\
\n w: writable\
\n x: program account (inner instructions excluded)\
"
),
)
.subcommand(
@@ -2095,7 +1967,6 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
.value_name("SEED_STRING")
.takes_value(true)
.required(true)
.validator(is_derived_address_seed)
.help("The seed. Must not take more than 32 bytes to encode as utf-8"),
)
.arg(
@@ -2216,29 +2087,6 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
.takes_value(false)
.help("Return signature immediately after submitting the transaction, instead of waiting for confirmations"),
)
.arg(
Arg::with_name("derived_address_seed")
.long("derived-address-seed")
.takes_value(true)
.value_name("SEED_STRING")
.requires("derived_address_program_id")
.validator(is_derived_address_seed)
.hidden(true)
)
.arg(
Arg::with_name("derived_address_program_id")
.long("derived-address-program-id")
.takes_value(true)
.value_name("PROGRAM_ID")
.requires("derived_address_seed")
.hidden(true)
)
.arg(
Arg::with_name("allow_unfunded_recipient")
.long("allow-unfunded-recipient")
.takes_value(false)
.help("Complete the transfer even if the recipient address is not funded")
)
.offline_args()
.nonce_args(false)
.arg(fee_payer_arg()),
@@ -2288,7 +2136,6 @@ mod tests {
signature::{keypair_from_seed, read_keypair_file, write_keypair_file, Keypair, Presigner},
transaction::TransactionError,
};
use solana_transaction_status::TransactionConfirmationStatus;
use std::path::PathBuf;
fn make_tmp_path(name: &str) -> String {
@@ -2529,12 +2376,12 @@ mod tests {
);
// Test Deploy Subcommand
let test_command =
let test_deploy =
test_commands
.clone()
.get_matches_from(vec!["test", "deploy", "/Users/test/program.o"]);
assert_eq!(
parse_command(&test_command, &default_signer, &mut None).unwrap(),
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Deploy {
program_location: "/Users/test/program.o".to_string(),
@@ -2549,14 +2396,14 @@ mod tests {
let custom_address = Keypair::new();
let custom_address_file = make_tmp_path("custom_address_file");
write_keypair_file(&custom_address, &custom_address_file).unwrap();
let test_command = test_commands.clone().get_matches_from(vec![
let test_deploy = test_commands.clone().get_matches_from(vec![
"test",
"deploy",
"/Users/test/program.o",
&custom_address_file,
]);
assert_eq!(
parse_command(&test_command, &default_signer, &mut None).unwrap(),
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Deploy {
program_location: "/Users/test/program.o".to_string(),
@@ -2682,7 +2529,6 @@ mod tests {
},
amount: SpendAmount::Some(30),
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -2702,7 +2548,6 @@ mod tests {
withdraw_authority: 0,
custodian: None,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -2717,7 +2562,6 @@ mod tests {
stake_account_pubkey,
stake_authority: 0,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -2732,7 +2576,6 @@ mod tests {
stake_account_pubkey,
stake_authority: 0,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -2753,7 +2596,6 @@ mod tests {
source_stake_account_pubkey,
stake_authority: 1,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -2888,7 +2730,6 @@ mod tests {
use_deprecated_loader: false,
allow_excessive_balance: false,
};
config.output_format = OutputFormat::JsonCompact;
let result = process_command(&config);
let json: Value = serde_json::from_str(&result.unwrap()).unwrap();
let program_id = json
@@ -2941,15 +2782,11 @@ mod tests {
to: to_pubkey,
from: 0,
sign_only: false,
dump_transaction_message: false,
allow_unfunded_recipient: false,
no_wait: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
},
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
}
@@ -2967,26 +2804,21 @@ mod tests {
to: to_pubkey,
from: 0,
sign_only: false,
dump_transaction_message: false,
allow_unfunded_recipient: false,
no_wait: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
},
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
}
);
// Test Transfer no-wait and --allow-unfunded-recipient
// Test Transfer no-wait
let test_transfer = test_commands.clone().get_matches_from(vec![
"test",
"transfer",
"--no-wait",
"--allow-unfunded-recipient",
&to_string,
"42",
]);
@@ -2998,15 +2830,11 @@ mod tests {
to: to_pubkey,
from: 0,
sign_only: false,
dump_transaction_message: false,
allow_unfunded_recipient: true,
no_wait: true,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
},
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
}
@@ -3032,15 +2860,11 @@ mod tests {
to: to_pubkey,
from: 0,
sign_only: true,
dump_transaction_message: false,
allow_unfunded_recipient: false,
no_wait: false,
blockhash_query: BlockhashQuery::None(blockhash),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
},
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
}
@@ -3071,8 +2895,6 @@ mod tests {
to: to_pubkey,
from: 0,
sign_only: false,
dump_transaction_message: false,
allow_unfunded_recipient: false,
no_wait: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::Cluster,
@@ -3081,8 +2903,6 @@ mod tests {
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
},
signers: vec![Presigner::new(&from_pubkey, &from_sig).into()],
}
@@ -3114,8 +2934,6 @@ mod tests {
to: to_pubkey,
from: 0,
sign_only: false,
dump_transaction_message: false,
allow_unfunded_recipient: false,
no_wait: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_address),
@@ -3124,8 +2942,6 @@ mod tests {
nonce_account: Some(nonce_address),
nonce_authority: 1,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
},
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),
@@ -3133,40 +2949,5 @@ mod tests {
],
}
);
//Test Transfer Subcommand, with seed
let derived_address_seed = "seed".to_string();
let derived_address_program_id = "STAKE";
let test_transfer = test_commands.clone().get_matches_from(vec![
"test",
"transfer",
&to_string,
"42",
"--derived-address-seed",
&derived_address_seed,
"--derived-address-program-id",
derived_address_program_id,
]);
assert_eq!(
parse_command(&test_transfer, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Transfer {
amount: SpendAmount::Some(42_000_000_000),
to: to_pubkey,
from: 0,
sign_only: false,
dump_transaction_message: false,
allow_unfunded_recipient: false,
no_wait: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: Some(derived_address_seed),
derived_address_program_id: Some(solana_stake_program::id()),
},
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into(),],
}
);
}
}

View File

@@ -3,6 +3,7 @@ use crate::{
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
stake::is_stake_program_v2_enabled,
};
use chrono::{Local, TimeZone};
use clap::{value_t, value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand};
use console::{style, Emoji};
use serde::{Deserialize, Serialize};
@@ -24,9 +25,8 @@ use solana_client::{
pubsub_client::PubsubClient,
rpc_client::{GetConfirmedSignaturesForAddress2Config, RpcClient},
rpc_config::{
RpcAccountInfoConfig, RpcConfirmedBlockConfig, RpcConfirmedTransactionConfig,
RpcLargestAccountsConfig, RpcLargestAccountsFilter, RpcProgramAccountsConfig,
RpcTransactionLogsConfig, RpcTransactionLogsFilter,
RpcAccountInfoConfig, RpcLargestAccountsConfig, RpcLargestAccountsFilter,
RpcProgramAccountsConfig, RpcTransactionLogsConfig, RpcTransactionLogsFilter,
},
rpc_filter,
rpc_response::SlotInfo,
@@ -135,17 +135,7 @@ impl ClusterQuerySubCommands for App<'_, '_> {
SubCommand::with_name("cluster-version")
.about("Get the version of the cluster entrypoint"),
)
.subcommand(
SubCommand::with_name("fees")
.about("Display current cluster fees")
.arg(
Arg::with_name("blockhash")
.long("blockhash")
.takes_value(true)
.value_name("BLOCKHASH")
.validator(is_hash)
.help("Query fees for BLOCKHASH instead of the the most recent blockhash")
),
.subcommand(SubCommand::with_name("fees").about("Display current cluster fees"),
)
.subcommand(
SubCommand::with_name("first-available-block")
@@ -743,10 +733,6 @@ pub fn process_catchup(
}
};
let start_node_slot = get_slot_while_retrying(&node_client)?;
let start_rpc_slot = get_slot_while_retrying(rpc_client)?;
let start_slot_distance = start_rpc_slot as i64 - start_node_slot as i64;
let mut total_sleep_interval = 0;
loop {
// humbly retry; the reference node (rpc_client) could be spotty,
// especially if pointing to api.meinnet-beta.solana.com at times
@@ -763,37 +749,14 @@ pub fn process_catchup(
let slot_distance = rpc_slot as i64 - node_slot as i64;
let slots_per_second =
(previous_slot_distance - slot_distance) as f64 / f64::from(sleep_interval);
let average_time_remaining = if slot_distance == 0 || total_sleep_interval == 0 {
let time_remaining = (slot_distance as f64 / slots_per_second).round();
let time_remaining = if !time_remaining.is_normal() || time_remaining <= 0.0 {
"".to_string()
} else {
let distance_delta = start_slot_distance as i64 - slot_distance as i64;
let average_catchup_slots_per_second =
distance_delta as f64 / f64::from(total_sleep_interval);
let average_time_remaining =
(slot_distance as f64 / average_catchup_slots_per_second).round();
if !average_time_remaining.is_normal() {
"".to_string()
} else if average_time_remaining < 0.0 {
format!(
" (AVG: {:.1} slots/second (falling))",
average_catchup_slots_per_second
)
} else {
// important not to miss next scheduled lead slots
let total_node_slot_delta = node_slot as i64 - start_node_slot as i64;
let average_node_slots_per_second =
total_node_slot_delta as f64 / f64::from(total_sleep_interval);
let expected_finish_slot = (node_slot as f64
+ average_time_remaining as f64 * average_node_slots_per_second as f64)
.round();
format!(
" (AVG: {:.1} slots/second, ETA: slot {} in {})",
average_catchup_slots_per_second,
expected_finish_slot,
humantime::format_duration(Duration::from_secs_f64(average_time_remaining))
)
}
format!(
". Time remaining: {}",
humantime::format_duration(Duration::from_secs_f64(time_remaining))
)
};
progress_bar.set_message(&format!(
@@ -818,7 +781,7 @@ pub fn process_catchup(
"gaining"
},
slots_per_second,
average_time_remaining
time_remaining
)
},
));
@@ -829,7 +792,6 @@ pub fn process_catchup(
sleep(Duration::from_secs(sleep_interval as u64));
previous_rpc_slot = rpc_slot;
previous_slot_distance = slot_distance;
total_sleep_interval += sleep_interval;
}
}
@@ -859,35 +821,14 @@ pub fn process_cluster_version(rpc_client: &RpcClient, config: &CliConfig) -> Pr
}
}
pub fn process_fees(
rpc_client: &RpcClient,
config: &CliConfig,
blockhash: Option<&Hash>,
) -> ProcessResult {
let fees = if let Some(recent_blockhash) = blockhash {
let result = rpc_client.get_fee_calculator_for_blockhash_with_commitment(
recent_blockhash,
config.commitment,
)?;
if let Some(fee_calculator) = result.value {
CliFees::some(
result.context.slot,
*recent_blockhash,
fee_calculator.lamports_per_signature,
None,
)
} else {
CliFees::none()
}
} else {
let result = rpc_client.get_recent_blockhash_with_commitment(config.commitment)?;
let (recent_blockhash, fee_calculator, last_valid_slot) = result.value;
CliFees::some(
result.context.slot,
recent_blockhash,
fee_calculator.lamports_per_signature,
Some(last_valid_slot),
)
pub fn process_fees(rpc_client: &RpcClient, config: &CliConfig) -> ProcessResult {
let result = rpc_client.get_recent_blockhash_with_commitment(config.commitment)?;
let (recent_blockhash, fee_calculator, last_valid_slot) = result.value;
let fees = CliFees {
slot: result.context.slot,
blockhash: recent_blockhash.to_string(),
lamports_per_signature: fee_calculator.lamports_per_signature,
last_valid_slot,
};
Ok(config.output_format.formatted_string(&fees))
}
@@ -955,7 +896,7 @@ pub fn process_leader_schedule(
pub fn process_get_block(
rpc_client: &RpcClient,
config: &CliConfig,
_config: &CliConfig,
slot: Option<Slot>,
) -> ProcessResult {
let slot = if let Some(slot) = slot {
@@ -964,21 +905,72 @@ pub fn process_get_block(
rpc_client.get_slot_with_commitment(CommitmentConfig::finalized())?
};
let encoded_confirmed_block = rpc_client
.get_confirmed_block_with_config(
slot,
RpcConfirmedBlockConfig {
encoding: Some(UiTransactionEncoding::Base64),
commitment: Some(CommitmentConfig::confirmed()),
..RpcConfirmedBlockConfig::default()
},
)?
.into();
let cli_block = CliBlock {
encoded_confirmed_block,
slot,
};
Ok(config.output_format.formatted_string(&cli_block))
let mut block =
rpc_client.get_confirmed_block_with_encoding(slot, UiTransactionEncoding::Base64)?;
println!("Slot: {}", slot);
println!("Parent Slot: {}", block.parent_slot);
println!("Blockhash: {}", block.blockhash);
println!("Previous Blockhash: {}", block.previous_blockhash);
if let Some(block_time) = block.block_time {
println!("Block Time: {:?}", Local.timestamp(block_time, 0));
}
if !block.rewards.is_empty() {
block.rewards.sort_by(|a, b| a.pubkey.cmp(&b.pubkey));
let mut total_rewards = 0;
println!("Rewards:",);
println!(
" {:<44} {:^15} {:<15} {:<20} {:>14}",
"Address", "Type", "Amount", "New Balance", "Percent Change"
);
for reward in block.rewards {
let sign = if reward.lamports < 0 { "-" } else { "" };
total_rewards += reward.lamports;
println!(
" {:<44} {:^15} {:>15} {}",
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)
),
if reward.post_balance == 0 {
" - -".to_string()
} else {
format!(
"{:<19.9} {:>13.9}%",
lamports_to_sol(reward.post_balance),
(reward.lamports.abs() as f64
/ (reward.post_balance as f64 - reward.lamports as f64))
* 100.0
)
}
);
}
let sign = if total_rewards < 0 { "-" } else { "" };
println!(
"Total Rewards: {}{:<12.9}",
sign,
lamports_to_sol(total_rewards.abs() as u64)
);
}
for (index, transaction_with_meta) in block.transactions.iter().enumerate() {
println!("Transaction {}:", index);
println_transaction(
&transaction_with_meta.transaction.decode().unwrap(),
&transaction_with_meta.meta,
" ",
None,
);
}
Ok("".to_string())
}
pub fn process_get_block_time(
@@ -1002,21 +994,7 @@ pub fn process_get_epoch(rpc_client: &RpcClient, _config: &CliConfig) -> Process
}
pub fn process_get_epoch_info(rpc_client: &RpcClient, config: &CliConfig) -> ProcessResult {
let epoch_info = rpc_client.get_epoch_info()?;
let average_slot_time_ms = rpc_client
.get_recent_performance_samples(Some(60))
.ok()
.and_then(|samples| {
let (slots, secs) = samples.iter().fold((0, 0), |(slots, secs), sample| {
(slots + sample.num_slots, secs + sample.sample_period_secs)
});
(secs as u64).saturating_mul(1000).checked_div(slots)
})
.unwrap_or(clock::DEFAULT_MS_PER_SLOT);
let epoch_info = CliEpochInfo {
epoch_info,
average_slot_time_ms,
};
let epoch_info: CliEpochInfo = rpc_client.get_epoch_info()?.into();
Ok(config.output_format.formatted_string(&epoch_info))
}
@@ -1031,8 +1009,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 epoch_info = rpc_client.get_epoch_info()?;
Ok(epoch_info.block_height.to_string())
let epoch_info: CliEpochInfo = rpc_client.get_epoch_info()?.into();
Ok(epoch_info.epoch_info.block_height.to_string())
}
pub fn parse_show_block_production(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
@@ -1361,7 +1339,9 @@ pub fn process_ping(
// Sleep for half a slot
if signal_receiver
.recv_timeout(Duration::from_millis(clock::DEFAULT_MS_PER_SLOT / 2))
.recv_timeout(Duration::from_millis(
500 * clock::DEFAULT_TICKS_PER_SLOT / clock::DEFAULT_TICKS_PER_SECOND,
))
.is_ok()
{
break 'mainloop;
@@ -1826,7 +1806,6 @@ pub fn process_transaction_history(
before,
until,
limit: Some(limit),
commitment: Some(CommitmentConfig::confirmed()),
},
)?;
@@ -1843,13 +1822,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()),
);
@@ -1859,13 +1834,9 @@ pub fn process_transaction_history(
if show_transactions {
if let Ok(signature) = result.signature.parse::<Signature>() {
match rpc_client.get_confirmed_transaction_with_config(
&signature,
RpcConfirmedTransactionConfig {
encoding: Some(UiTransactionEncoding::Base64),
commitment: Some(CommitmentConfig::confirmed()),
},
) {
match rpc_client
.get_confirmed_transaction(&signature, UiTransactionEncoding::Base64)
{
Ok(confirmed_transaction) => {
println_transaction(
&confirmed_transaction
@@ -1876,7 +1847,6 @@ pub fn process_transaction_history(
&confirmed_transaction.transaction.meta,
" ",
None,
None,
);
}
Err(err) => println!(" Unable to get confirmed transaction details: {}", err),
@@ -1994,24 +1964,7 @@ mod tests {
assert_eq!(
parse_command(&test_fees, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Fees { blockhash: None },
signers: vec![],
}
);
let blockhash = Hash::new_unique();
let test_fees = test_commands.clone().get_matches_from(vec![
"test",
"fees",
"--blockhash",
&blockhash.to_string(),
]);
assert_eq!(
parse_command(&test_fees, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Fees {
blockhash: Some(blockhash)
},
command: CliCommand::Fees,
signers: vec![],
}
);

View File

@@ -70,7 +70,7 @@ impl fmt::Display for CliFeatures {
f,
"{}",
style(format!(
"{:<44} | {:<27} | {}",
"{:<44} {:<28} {}",
"Feature", "Status", "Description"
))
.bold()
@@ -79,7 +79,7 @@ impl fmt::Display for CliFeatures {
for feature in &self.features {
writeln!(
f,
"{:<44} | {:<27} | {}",
"{:<44} {:<28} {}",
feature.id,
match feature.status {
CliFeatureStatus::Inactive => style("inactive".to_string()).red(),
@@ -221,7 +221,7 @@ pub fn process_feature_subcommand(
}
}
fn active_stake_by_feature_set(rpc_client: &RpcClient) -> Result<HashMap<u32, f64>, ClientError> {
fn active_stake_by_feature_set(rpc_client: &RpcClient) -> Result<HashMap<u32, u64>, ClientError> {
// Validator identity -> feature set
let feature_set_map = rpc_client
.get_cluster_nodes()?
@@ -239,7 +239,7 @@ fn active_stake_by_feature_set(rpc_client: &RpcClient) -> Result<HashMap<u32, f6
.sum();
// Sum all active stake by feature set
let mut active_stake_by_feature_set: HashMap<u32, u64> = HashMap::new();
let mut active_stake_by_feature_set = HashMap::new();
for vote_account in vote_accounts.current {
if let Some(Some(feature_set)) = feature_set_map.get(&vote_account.node_pubkey) {
*active_stake_by_feature_set.entry(*feature_set).or_default() +=
@@ -251,15 +251,11 @@ fn active_stake_by_feature_set(rpc_client: &RpcClient) -> Result<HashMap<u32, f6
}
}
Ok(active_stake_by_feature_set
.into_iter()
.map(|(feature_set, active_stake)| {
(
feature_set,
active_stake as f64 * 100. / total_active_stake as f64,
)
})
.collect())
// Convert active stake to a percentage so the caller doesn't need `total_active_stake`
for (_, val) in active_stake_by_feature_set.iter_mut() {
*val = *val * 100 / total_active_stake;
}
Ok(active_stake_by_feature_set)
}
// Feature activation is only allowed when 95% of the active stake is on the current feature set
@@ -270,7 +266,7 @@ fn feature_activation_allowed(rpc_client: &RpcClient, quiet: bool) -> Result<boo
let feature_activation_allowed = active_stake_by_feature_set
.get(&my_feature_set)
.map(|percentage| *percentage >= 95.)
.map(|percentage| *percentage >= 95)
.unwrap_or(false);
if !feature_activation_allowed && !quiet {
@@ -287,15 +283,15 @@ fn feature_activation_allowed(rpc_client: &RpcClient, quiet: bool) -> Result<boo
}
println!(
"{}",
style(format!("Tool Feature Set: {}", my_feature_set)).bold()
style(format!("Tool Feture Set: {}", my_feature_set)).bold()
);
println!("{}", style("Cluster Feature Sets and Stakes:").bold());
for (feature_set, percentage) in active_stake_by_feature_set.iter() {
if *feature_set == 0 {
println!(" unknown - {:.2}%", percentage);
println!("unknown - {}%", percentage);
} else {
println!(
" {:<10} - {:.2}% {}",
"{} - {}% {}",
feature_set,
percentage,
if *feature_set == my_feature_set {

View File

@@ -1,4 +1,3 @@
#![allow(clippy::integer_arithmetic)]
macro_rules! ACCOUNT_STRING {
() => {
r#", one of:

File diff suppressed because it is too large Load Diff

View File

@@ -1,38 +1,21 @@
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(
pub fn get_leader_tpu(
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?
) -> Option<SocketAddr> {
leader_schedule?
.iter()
.find(|(_pubkey, slots)| slots.iter().any(|slot| *slot as u64 == slot_index))
.and_then(|(pubkey, _)| {
cluster_nodes?
.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)
})
.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(

View File

@@ -107,22 +107,15 @@ where
return Err(CliError::InsufficientFundsForSpendAndFee(
lamports_to_sol(spend),
lamports_to_sol(fee),
*from_pubkey,
));
}
} else {
if from_balance < spend {
return Err(CliError::InsufficientFundsForSpend(
lamports_to_sol(spend),
*from_pubkey,
));
return Err(CliError::InsufficientFundsForSpend(lamports_to_sol(spend)));
}
if !check_account_for_balance_with_commitment(rpc_client, fee_pubkey, fee, commitment)?
{
return Err(CliError::InsufficientFundsForFee(
lamports_to_sol(fee),
*fee_pubkey,
));
return Err(CliError::InsufficientFundsForFee(lamports_to_sol(fee)));
}
}
Ok((message, spend))

View File

@@ -19,15 +19,14 @@ use solana_clap_utils::{
ArgConstant,
};
use solana_cli_output::{
return_signers_with_config, CliEpochReward, CliStakeHistory, CliStakeHistoryEntry,
CliStakeState, CliStakeType, ReturnSignersConfig,
return_signers, CliEpochReward, CliStakeHistory, CliStakeHistoryEntry, CliStakeState,
CliStakeType,
};
use solana_client::{
blockhash_query::BlockhashQuery,
client_error::{ClientError, ClientErrorKind},
nonce_utils,
rpc_client::RpcClient,
rpc_config::RpcConfirmedBlockConfig,
rpc_custom_error,
rpc_request::{self, DELINQUENT_VALIDATOR_SLOT_DISTANCE},
};
@@ -269,7 +268,7 @@ impl StakeSubCommands for App<'_, '_> {
.arg(
Arg::with_name("split_stake_account")
.index(2)
.value_name("SPLIT_STAKE_ACCOUNT")
.value_name("ACCOUNT_KEYPAIR")
.takes_value(true)
.required(true)
.validator(is_valid_signer)
@@ -289,7 +288,7 @@ impl StakeSubCommands for App<'_, '_> {
.long("seed")
.value_name("STRING")
.takes_value(true)
.help("Seed for address generation; if specified, the resulting account will be at a derived address of the SPLIT_STAKE_ACCOUNT pubkey")
.help("Seed for address generation; if specified, the resulting account will be at a derived address of the SPLIT STAKE ACCOUNT pubkey")
)
.arg(stake_authority_arg())
.offline_args()
@@ -442,7 +441,6 @@ pub fn parse_stake_create_account(
let withdrawer = pubkey_of_signer(matches, WITHDRAW_AUTHORITY_ARG.name, wallet_manager)?;
let amount = SpendAmount::new_from_matches(matches, "amount");
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name);
let blockhash_query = BlockhashQuery::new_from_matches(matches);
let nonce_account = pubkey_of_signer(matches, NONCE_ARG.name, wallet_manager)?;
let (nonce_authority, nonce_authority_pubkey) =
@@ -472,7 +470,6 @@ pub fn parse_stake_create_account(
},
amount,
sign_only,
dump_transaction_message,
blockhash_query,
nonce_account,
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
@@ -494,7 +491,6 @@ pub fn parse_stake_delegate_stake(
pubkey_of_signer(matches, "vote_account_pubkey", wallet_manager)?.unwrap();
let force = matches.is_present("force");
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name);
let blockhash_query = BlockhashQuery::new_from_matches(matches);
let nonce_account = pubkey_of(matches, NONCE_ARG.name);
let (stake_authority, stake_authority_pubkey) =
@@ -517,7 +513,6 @@ pub fn parse_stake_delegate_stake(
stake_authority: signer_info.index_of(stake_authority_pubkey).unwrap(),
force,
sign_only,
dump_transaction_message,
blockhash_query,
nonce_account,
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
@@ -570,7 +565,6 @@ pub fn parse_stake_authorize(
bulk_signers.push(authority);
};
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name);
let blockhash_query = BlockhashQuery::new_from_matches(matches);
let nonce_account = pubkey_of(matches, NONCE_ARG.name);
let (nonce_authority, nonce_authority_pubkey) =
@@ -606,7 +600,6 @@ pub fn parse_stake_authorize(
stake_account_pubkey,
new_authorizations,
sign_only,
dump_transaction_message,
blockhash_query,
nonce_account,
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
@@ -630,7 +623,6 @@ pub fn parse_split_stake(
let seed = matches.value_of("seed").map(|s| s.to_string());
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name);
let blockhash_query = BlockhashQuery::new_from_matches(matches);
let nonce_account = pubkey_of(matches, NONCE_ARG.name);
let (stake_authority, stake_authority_pubkey) =
@@ -651,7 +643,6 @@ pub fn parse_split_stake(
stake_account_pubkey,
stake_authority: signer_info.index_of(stake_authority_pubkey).unwrap(),
sign_only,
dump_transaction_message,
blockhash_query,
nonce_account,
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
@@ -675,7 +666,6 @@ pub fn parse_merge_stake(
let source_stake_account_pubkey = pubkey_of(matches, "source_stake_account_pubkey").unwrap();
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name);
let blockhash_query = BlockhashQuery::new_from_matches(matches);
let nonce_account = pubkey_of(matches, NONCE_ARG.name);
let (stake_authority, stake_authority_pubkey) =
@@ -697,7 +687,6 @@ pub fn parse_merge_stake(
source_stake_account_pubkey,
stake_authority: signer_info.index_of(stake_authority_pubkey).unwrap(),
sign_only,
dump_transaction_message,
blockhash_query,
nonce_account,
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
@@ -715,7 +704,6 @@ pub fn parse_stake_deactivate_stake(
let stake_account_pubkey =
pubkey_of_signer(matches, "stake_account_pubkey", wallet_manager)?.unwrap();
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name);
let blockhash_query = BlockhashQuery::new_from_matches(matches);
let nonce_account = pubkey_of(matches, NONCE_ARG.name);
let (stake_authority, stake_authority_pubkey) =
@@ -736,7 +724,6 @@ pub fn parse_stake_deactivate_stake(
stake_account_pubkey,
stake_authority: signer_info.index_of(stake_authority_pubkey).unwrap(),
sign_only,
dump_transaction_message,
blockhash_query,
nonce_account,
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
@@ -757,7 +744,6 @@ pub fn parse_stake_withdraw_stake(
pubkey_of_signer(matches, "destination_account_pubkey", wallet_manager)?.unwrap();
let lamports = lamports_of_sol(matches, "amount").unwrap();
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name);
let blockhash_query = BlockhashQuery::new_from_matches(matches);
let nonce_account = pubkey_of(matches, NONCE_ARG.name);
let (withdraw_authority, withdraw_authority_pubkey) =
@@ -784,7 +770,6 @@ pub fn parse_stake_withdraw_stake(
lamports,
withdraw_authority: signer_info.index_of(withdraw_authority_pubkey).unwrap(),
sign_only,
dump_transaction_message,
blockhash_query,
nonce_account,
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
@@ -807,7 +792,6 @@ pub fn parse_stake_set_lockup(
let new_custodian = pubkey_of_signer(matches, "new_custodian", wallet_manager)?;
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name);
let blockhash_query = BlockhashQuery::new_from_matches(matches);
let nonce_account = pubkey_of(matches, NONCE_ARG.name);
@@ -833,7 +817,6 @@ pub fn parse_stake_set_lockup(
},
custodian: signer_info.index_of(custodian_pubkey).unwrap(),
sign_only,
dump_transaction_message,
blockhash_query,
nonce_account,
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
@@ -878,7 +861,6 @@ pub fn process_create_stake_account(
lockup: &Lockup,
amount: SpendAmount,
sign_only: bool,
dump_transaction_message: bool,
blockhash_query: &BlockhashQuery,
nonce_account: Option<&Pubkey>,
nonce_authority: SignerIndex,
@@ -988,13 +970,7 @@ pub fn process_create_stake_account(
let mut tx = Transaction::new_unsigned(message);
if sign_only {
tx.try_partial_sign(&config.signers, recent_blockhash)?;
return_signers_with_config(
&tx,
&config.output_format,
&ReturnSignersConfig {
dump_transaction_message,
},
)
return_signers(&tx, &config.output_format)
} else {
tx.try_sign(&config.signers, recent_blockhash)?;
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
@@ -1010,7 +986,6 @@ pub fn process_stake_authorize(
new_authorizations: &[(StakeAuthorize, Pubkey, SignerIndex)],
custodian: Option<SignerIndex>,
sign_only: bool,
dump_transaction_message: bool,
blockhash_query: &BlockhashQuery,
nonce_account: Option<Pubkey>,
nonce_authority: SignerIndex,
@@ -1053,13 +1028,7 @@ pub fn process_stake_authorize(
if sign_only {
tx.try_partial_sign(&config.signers, recent_blockhash)?;
return_signers_with_config(
&tx,
&config.output_format,
&ReturnSignersConfig {
dump_transaction_message,
},
)
return_signers(&tx, &config.output_format)
} else {
tx.try_sign(&config.signers, recent_blockhash)?;
if let Some(nonce_account) = &nonce_account {
@@ -1089,7 +1058,6 @@ pub fn process_deactivate_stake_account(
stake_account_pubkey: &Pubkey,
stake_authority: SignerIndex,
sign_only: bool,
dump_transaction_message: bool,
blockhash_query: &BlockhashQuery,
nonce_account: Option<Pubkey>,
nonce_authority: SignerIndex,
@@ -1119,13 +1087,7 @@ pub fn process_deactivate_stake_account(
if sign_only {
tx.try_partial_sign(&config.signers, recent_blockhash)?;
return_signers_with_config(
&tx,
&config.output_format,
&ReturnSignersConfig {
dump_transaction_message,
},
)
return_signers(&tx, &config.output_format)
} else {
tx.try_sign(&config.signers, recent_blockhash)?;
if let Some(nonce_account) = &nonce_account {
@@ -1158,7 +1120,6 @@ pub fn process_withdraw_stake(
withdraw_authority: SignerIndex,
custodian: Option<SignerIndex>,
sign_only: bool,
dump_transaction_message: bool,
blockhash_query: &BlockhashQuery,
nonce_account: Option<&Pubkey>,
nonce_authority: SignerIndex,
@@ -1194,13 +1155,7 @@ pub fn process_withdraw_stake(
if sign_only {
tx.try_partial_sign(&config.signers, recent_blockhash)?;
return_signers_with_config(
&tx,
&config.output_format,
&ReturnSignersConfig {
dump_transaction_message,
},
)
return_signers(&tx, &config.output_format)
} else {
tx.try_sign(&config.signers, recent_blockhash)?;
if let Some(nonce_account) = &nonce_account {
@@ -1230,7 +1185,6 @@ pub fn process_split_stake(
stake_account_pubkey: &Pubkey,
stake_authority: SignerIndex,
sign_only: bool,
dump_transaction_message: bool,
blockhash_query: &BlockhashQuery,
nonce_account: Option<Pubkey>,
nonce_authority: SignerIndex,
@@ -1340,13 +1294,7 @@ pub fn process_split_stake(
if sign_only {
tx.try_partial_sign(&config.signers, recent_blockhash)?;
return_signers_with_config(
&tx,
&config.output_format,
&ReturnSignersConfig {
dump_transaction_message,
},
)
return_signers(&tx, &config.output_format)
} else {
tx.try_sign(&config.signers, recent_blockhash)?;
if let Some(nonce_account) = &nonce_account {
@@ -1377,7 +1325,6 @@ pub fn process_merge_stake(
source_stake_account_pubkey: &Pubkey,
stake_authority: SignerIndex,
sign_only: bool,
dump_transaction_message: bool,
blockhash_query: &BlockhashQuery,
nonce_account: Option<Pubkey>,
nonce_authority: SignerIndex,
@@ -1445,13 +1392,7 @@ pub fn process_merge_stake(
if sign_only {
tx.try_partial_sign(&config.signers, recent_blockhash)?;
return_signers_with_config(
&tx,
&config.output_format,
&ReturnSignersConfig {
dump_transaction_message,
},
)
return_signers(&tx, &config.output_format)
} else {
tx.try_sign(&config.signers, recent_blockhash)?;
if let Some(nonce_account) = &nonce_account {
@@ -1486,7 +1427,6 @@ pub fn process_stake_set_lockup(
lockup: &mut LockupArgs,
custodian: SignerIndex,
sign_only: bool,
dump_transaction_message: bool,
blockhash_query: &BlockhashQuery,
nonce_account: Option<Pubkey>,
nonce_authority: SignerIndex,
@@ -1518,13 +1458,7 @@ pub fn process_stake_set_lockup(
if sign_only {
tx.try_partial_sign(&config.signers, recent_blockhash)?;
return_signers_with_config(
&tx,
&config.output_format,
&ReturnSignersConfig {
dump_transaction_message,
},
)
return_signers(&tx, &config.output_format)
} else {
tx.try_sign(&config.signers, recent_blockhash)?;
if let Some(nonce_account) = &nonce_account {
@@ -1675,9 +1609,9 @@ pub(crate) fn fetch_epoch_rewards(
.get(0)
.ok_or_else(|| format!("Unable to fetch first confirmed block for epoch {}", epoch))?;
let first_confirmed_block = match rpc_client.get_confirmed_block_with_config(
let first_confirmed_block = match rpc_client.get_confirmed_block_with_encoding(
first_confirmed_block_in_epoch,
RpcConfirmedBlockConfig::rewards_only(),
solana_transaction_status::UiTransactionEncoding::Base64,
) {
Ok(first_confirmed_block) => first_confirmed_block,
Err(ClientError {
@@ -1703,7 +1637,7 @@ pub(crate) fn fetch_epoch_rewards(
};
// Rewards for the previous epoch are found in the first confirmed block of the current epoch
let previous_epoch_rewards = first_confirmed_block.rewards.unwrap_or_default();
let previous_epoch_rewards = first_confirmed_block.rewards;
if let Some((effective_slot, epoch_end_time, epoch_rewards)) = epoch_info {
let wallclock_epoch_duration = if epoch_end_time > epoch_start_time {
@@ -1813,10 +1747,9 @@ pub fn process_show_stake_history(
use_lamports_unit: bool,
) -> ProcessResult {
let stake_history_account = rpc_client.get_account(&stake_history::id())?;
let stake_history =
from_account::<StakeHistory, _>(&stake_history_account).ok_or_else(|| {
CliError::RpcRequestError("Failed to deserialize stake history".to_string())
})?;
let stake_history = from_account::<StakeHistory>(&stake_history_account).ok_or_else(|| {
CliError::RpcRequestError("Failed to deserialize stake history".to_string())
})?;
let mut entries: Vec<CliStakeHistoryEntry> = vec![];
for entry in stake_history.deref() {
@@ -1838,7 +1771,6 @@ pub fn process_delegate_stake(
stake_authority: SignerIndex,
force: bool,
sign_only: bool,
dump_transaction_message: bool,
blockhash_query: &BlockhashQuery,
nonce_account: Option<Pubkey>,
nonce_authority: SignerIndex,
@@ -1923,13 +1855,7 @@ pub fn process_delegate_stake(
if sign_only {
tx.try_partial_sign(&config.signers, recent_blockhash)?;
return_signers_with_config(
&tx,
&config.output_format,
&ReturnSignersConfig {
dump_transaction_message,
},
)
return_signers(&tx, &config.output_format)
} else {
tx.try_sign(&config.signers, recent_blockhash)?;
if let Some(nonce_account) = &nonce_account {
@@ -2026,7 +1952,6 @@ mod tests {
(StakeAuthorize::Withdrawer, new_withdraw_authority, 0,),
],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -2062,7 +1987,6 @@ mod tests {
(StakeAuthorize::Withdrawer, new_withdraw_authority, 2,),
],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -2102,7 +2026,6 @@ mod tests {
(StakeAuthorize::Withdrawer, new_withdraw_authority, 1,),
],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -2131,7 +2054,6 @@ mod tests {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, new_stake_authority, 0,),],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -2157,7 +2079,6 @@ mod tests {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, new_stake_authority, 1,),],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -2189,7 +2110,6 @@ mod tests {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, new_stake_authority, 1,),],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -2222,7 +2142,6 @@ mod tests {
0,
),],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -2252,7 +2171,6 @@ mod tests {
1,
),],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -2288,7 +2206,6 @@ mod tests {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, stake_account_pubkey, 0)],
sign_only: true,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::None(blockhash),
nonce_account: None,
nonce_authority: 0,
@@ -2323,7 +2240,6 @@ mod tests {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, stake_account_pubkey, 0)],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::Cluster,
blockhash
@@ -2371,7 +2287,6 @@ mod tests {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, stake_account_pubkey, 0)],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_account),
blockhash
@@ -2405,7 +2320,6 @@ mod tests {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, stake_account_pubkey, 0)],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::Cluster,
blockhash
@@ -2444,7 +2358,6 @@ mod tests {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, stake_account_pubkey, 0)],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_account_pubkey),
blockhash
@@ -2482,7 +2395,6 @@ mod tests {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, stake_account_pubkey, 0)],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -2518,7 +2430,6 @@ mod tests {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, stake_account_pubkey, 0)],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::Cluster,
blockhash
@@ -2569,7 +2480,6 @@ mod tests {
},
amount: SpendAmount::Some(50_000_000_000),
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -2607,7 +2517,6 @@ mod tests {
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000_000_000),
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -2661,7 +2570,6 @@ mod tests {
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000_000_000),
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_account),
nonce_hash
@@ -2696,7 +2604,6 @@ mod tests {
stake_authority: 0,
force: false,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -2726,7 +2633,6 @@ mod tests {
stake_authority: 1,
force: false,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -2758,7 +2664,6 @@ mod tests {
stake_authority: 0,
force: true,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -2788,7 +2693,6 @@ mod tests {
stake_authority: 0,
force: false,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::Cluster,
blockhash
@@ -2819,7 +2723,6 @@ mod tests {
stake_authority: 0,
force: false,
sign_only: true,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::None(blockhash),
nonce_account: None,
nonce_authority: 0,
@@ -2854,7 +2757,6 @@ mod tests {
stake_authority: 0,
force: false,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::Cluster,
blockhash
@@ -2901,7 +2803,6 @@ mod tests {
stake_authority: 0,
force: false,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_account),
blockhash
@@ -2939,7 +2840,6 @@ mod tests {
stake_authority: 0,
force: false,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -2971,7 +2871,6 @@ mod tests {
withdraw_authority: 0,
custodian: None,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -3002,7 +2901,6 @@ mod tests {
withdraw_authority: 1,
custodian: None,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -3038,7 +2936,6 @@ mod tests {
withdraw_authority: 0,
custodian: Some(1),
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -3082,7 +2979,6 @@ mod tests {
withdraw_authority: 0,
custodian: None,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_account),
nonce_hash
@@ -3113,7 +3009,6 @@ mod tests {
stake_account_pubkey,
stake_authority: 0,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -3138,7 +3033,6 @@ mod tests {
stake_account_pubkey,
stake_authority: 1,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -3170,7 +3064,6 @@ mod tests {
stake_account_pubkey,
stake_authority: 0,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::Cluster,
blockhash
@@ -3198,7 +3091,6 @@ mod tests {
stake_account_pubkey,
stake_authority: 0,
sign_only: true,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::None(blockhash),
nonce_account: None,
nonce_authority: 0,
@@ -3230,7 +3122,6 @@ mod tests {
stake_account_pubkey,
stake_authority: 0,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::Cluster,
blockhash
@@ -3274,7 +3165,6 @@ mod tests {
stake_account_pubkey,
stake_authority: 0,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_account),
blockhash
@@ -3306,7 +3196,6 @@ mod tests {
stake_account_pubkey,
stake_authority: 0,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -3341,7 +3230,6 @@ mod tests {
stake_account_pubkey: stake_account_keypair.pubkey(),
stake_authority: 0,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -3403,7 +3291,6 @@ mod tests {
stake_account_pubkey: stake_account_keypair.pubkey(),
stake_authority: 0,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_account),
nonce_hash
@@ -3445,7 +3332,6 @@ mod tests {
source_stake_account_pubkey,
stake_authority: 0,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,

View File

@@ -293,15 +293,11 @@ fn test_create_account_with_seed() {
to: to_address,
from: 0,
sign_only: true,
dump_transaction_message: true,
allow_unfunded_recipient: true,
no_wait: false,
blockhash_query: BlockhashQuery::None(nonce_hash),
nonce_account: Some(nonce_address),
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
authority_config.output_format = OutputFormat::JsonCompact;
let sign_only_reply = process_command(&authority_config).unwrap();
@@ -318,8 +314,6 @@ fn test_create_account_with_seed() {
to: to_address,
from: 0,
sign_only: false,
dump_transaction_message: true,
allow_unfunded_recipient: true,
no_wait: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_address),
@@ -328,8 +322,6 @@ fn test_create_account_with_seed() {
nonce_account: Some(nonce_address),
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
process_command(&submit_config).unwrap();
check_recent_balance(241, &rpc_client, &nonce_address);

View File

@@ -59,7 +59,6 @@ fn test_cli_program_deploy_non_upgradeable() {
use_deprecated_loader: false,
allow_excessive_balance: false,
};
config.output_format = OutputFormat::JsonCompact;
let response = process_command(&config);
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
let program_id_str = json
@@ -192,7 +191,6 @@ fn test_cli_program_deploy_no_authority() {
is_final: true,
max_len: None,
});
config.output_format = OutputFormat::JsonCompact;
let response = process_command(&config);
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
let program_id_str = json
@@ -442,9 +440,6 @@ fn test_cli_program_deploy_with_authority() {
config.signers = vec![&keypair];
config.command = CliCommand::Program(ProgramCliCommand::Show {
account_pubkey: Some(program_pubkey),
authority_pubkey: keypair.pubkey(),
all: false,
use_lamports_unit: false,
});
let response = process_command(&config);
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
@@ -533,9 +528,6 @@ fn test_cli_program_deploy_with_authority() {
config.signers = vec![&keypair];
config.command = CliCommand::Program(ProgramCliCommand::Show {
account_pubkey: Some(program_pubkey),
authority_pubkey: keypair.pubkey(),
all: false,
use_lamports_unit: false,
});
let response = process_command(&config);
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
@@ -577,7 +569,7 @@ fn test_cli_program_write_buffer() {
.unwrap();
let minimum_balance_for_buffer_default = rpc_client
.get_minimum_balance_for_rent_exemption(
UpgradeableLoaderState::programdata_len(max_len).unwrap(),
UpgradeableLoaderState::programdata_len(max_len * 2).unwrap(),
)
.unwrap();
@@ -663,12 +655,9 @@ fn test_cli_program_write_buffer() {
);
// Get buffer authority
config.signers = vec![];
config.signers = vec![&keypair];
config.command = CliCommand::Program(ProgramCliCommand::Show {
account_pubkey: Some(buffer_keypair.pubkey()),
authority_pubkey: keypair.pubkey(),
all: false,
use_lamports_unit: false,
});
let response = process_command(&config);
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
@@ -756,12 +745,9 @@ fn test_cli_program_write_buffer() {
);
// Get buffer authority
config.signers = vec![];
config.signers = vec![&keypair];
config.command = CliCommand::Program(ProgramCliCommand::Show {
account_pubkey: Some(buffer_pubkey),
authority_pubkey: keypair.pubkey(),
all: false,
use_lamports_unit: false,
});
let response = process_command(&config);
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
@@ -776,60 +762,6 @@ fn test_cli_program_write_buffer() {
authority_keypair.pubkey(),
Pubkey::from_str(&authority_pubkey_str).unwrap()
);
// Close buffer
let close_account = rpc_client.get_account(&buffer_pubkey).unwrap();
assert_eq!(minimum_balance_for_buffer, close_account.lamports);
let recipient_pubkey = Pubkey::new_unique();
config.signers = vec![&keypair, &authority_keypair];
config.command = CliCommand::Program(ProgramCliCommand::Close {
account_pubkey: Some(buffer_pubkey),
recipient_pubkey,
authority_index: 1,
use_lamports_unit: false,
});
process_command(&config).unwrap();
rpc_client.get_account(&buffer_pubkey).unwrap_err();
let recipient_account = rpc_client.get_account(&recipient_pubkey).unwrap();
assert_eq!(minimum_balance_for_buffer, recipient_account.lamports);
// Write a buffer with default params
config.signers = vec![&keypair];
config.command = CliCommand::Program(ProgramCliCommand::WriteBuffer {
program_location: pathbuf.to_str().unwrap().to_string(),
buffer_signer_index: None,
buffer_pubkey: None,
buffer_authority_signer_index: None,
max_len: None,
});
config.output_format = OutputFormat::JsonCompact;
let response = process_command(&config);
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
let buffer_pubkey_str = json
.as_object()
.unwrap()
.get("buffer")
.unwrap()
.as_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;
config.signers = vec![&keypair];
config.command = CliCommand::Program(ProgramCliCommand::Close {
account_pubkey: Some(new_buffer_pubkey),
recipient_pubkey: keypair.pubkey(),
authority_index: 0,
use_lamports_unit: false,
});
process_command(&config).unwrap();
rpc_client.get_account(&new_buffer_pubkey).unwrap_err();
let recipient_account = rpc_client.get_account(&keypair.pubkey()).unwrap();
assert_eq!(
pre_lamports + minimum_balance_for_buffer,
recipient_account.lamports
);
}
#[test]
@@ -897,7 +829,6 @@ fn test_cli_program_set_buffer_authority() {
buffer_authority_index: Some(0),
new_buffer_authority: new_buffer_authority.pubkey(),
});
config.output_format = OutputFormat::JsonCompact;
let response = process_command(&config);
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
let new_buffer_authority_str = json
@@ -1095,9 +1026,6 @@ fn test_cli_program_show() {
config.signers = vec![&keypair];
config.command = CliCommand::Program(ProgramCliCommand::Show {
account_pubkey: Some(buffer_keypair.pubkey()),
authority_pubkey: keypair.pubkey(),
all: false,
use_lamports_unit: false,
});
let response = process_command(&config);
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
@@ -1147,17 +1075,13 @@ fn test_cli_program_show() {
max_len: Some(max_len),
});
config.output_format = OutputFormat::JsonCompact;
let min_slot = rpc_client.get_slot().unwrap();
process_command(&config).unwrap();
let max_slot = rpc_client.get_slot().unwrap();
let slot = rpc_client.get_slot().unwrap();
// Verify show
config.signers = vec![&keypair];
config.command = CliCommand::Program(ProgramCliCommand::Show {
account_pubkey: Some(program_keypair.pubkey()),
authority_pubkey: keypair.pubkey(),
all: false,
use_lamports_unit: false,
});
let response = process_command(&config);
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
@@ -1205,8 +1129,7 @@ fn test_cli_program_show() {
.unwrap()
.as_u64()
.unwrap();
assert!(deployed_slot >= min_slot);
assert!(deployed_slot <= max_slot);
assert_eq!(slot, deployed_slot);
let data_len = json
.as_object()
.unwrap()

View File

@@ -70,7 +70,6 @@ fn test_stake_delegation_force() {
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -87,7 +86,6 @@ fn test_stake_delegation_force() {
stake_authority: 0,
force: false,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -102,7 +100,6 @@ fn test_stake_delegation_force() {
stake_authority: 0,
force: true,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -154,7 +151,6 @@ fn test_seed_stake_delegation_and_deactivation() {
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -170,7 +166,6 @@ fn test_seed_stake_delegation_and_deactivation() {
stake_authority: 0,
force: true,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -183,7 +178,6 @@ fn test_seed_stake_delegation_and_deactivation() {
stake_account_pubkey: stake_address,
stake_authority: 0,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -230,7 +224,6 @@ fn test_stake_delegation_and_deactivation() {
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -247,7 +240,6 @@ fn test_stake_delegation_and_deactivation() {
stake_authority: 0,
force: true,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -260,7 +252,6 @@ fn test_stake_delegation_and_deactivation() {
stake_account_pubkey: stake_keypair.pubkey(),
stake_authority: 0,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -295,7 +286,7 @@ fn test_offline_stake_delegation_and_deactivation() {
config_offline.command = CliCommand::ClusterVersion;
let offline_keypair = Keypair::new();
config_offline.signers = vec![&offline_keypair];
// Verify that we cannot reach the cluster
// Verfiy that we cannot reach the cluster
process_command(&config_offline).unwrap_err();
request_and_confirm_airdrop(
@@ -328,7 +319,6 @@ fn test_offline_stake_delegation_and_deactivation() {
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -345,7 +335,6 @@ fn test_offline_stake_delegation_and_deactivation() {
stake_authority: 0,
force: true,
sign_only: true,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::None(blockhash),
nonce_account: None,
nonce_authority: 0,
@@ -365,7 +354,6 @@ fn test_offline_stake_delegation_and_deactivation() {
stake_authority: 0,
force: true,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
nonce_account: None,
nonce_authority: 0,
@@ -379,7 +367,6 @@ fn test_offline_stake_delegation_and_deactivation() {
stake_account_pubkey: stake_keypair.pubkey(),
stake_authority: 0,
sign_only: true,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::None(blockhash),
nonce_account: None,
nonce_authority: 0,
@@ -396,7 +383,6 @@ fn test_offline_stake_delegation_and_deactivation() {
stake_account_pubkey: stake_keypair.pubkey(),
stake_authority: 0,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
nonce_account: None,
nonce_authority: 0,
@@ -445,7 +431,6 @@ fn test_nonced_stake_delegation_and_deactivation() {
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -483,7 +468,6 @@ fn test_nonced_stake_delegation_and_deactivation() {
stake_authority: 0,
force: true,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_account.pubkey()),
nonce_hash,
@@ -509,7 +493,6 @@ fn test_nonced_stake_delegation_and_deactivation() {
stake_account_pubkey: stake_keypair.pubkey(),
stake_authority: 0,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_account.pubkey()),
nonce_hash,
@@ -552,7 +535,7 @@ fn test_stake_authorize() {
config_offline.json_rpc_url = String::default();
let offline_authority_pubkey = config_offline.signers[0].pubkey();
config_offline.command = CliCommand::ClusterVersion;
// Verify that we cannot reach the cluster
// Verfiy that we cannot reach the cluster
process_command(&config_offline).unwrap_err();
request_and_confirm_airdrop(
@@ -576,7 +559,6 @@ fn test_stake_authorize() {
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -593,7 +575,6 @@ fn test_stake_authorize() {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, online_authority_pubkey, 0)],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -622,7 +603,6 @@ fn test_stake_authorize() {
(StakeAuthorize::Withdrawer, withdraw_authority_pubkey, 0),
],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -646,7 +626,6 @@ fn test_stake_authorize() {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, offline_authority_pubkey, 1)],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -670,7 +649,6 @@ fn test_stake_authorize() {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, nonced_authority_pubkey, 0)],
sign_only: true,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::None(blockhash),
nonce_account: None,
nonce_authority: 0,
@@ -687,7 +665,6 @@ fn test_stake_authorize() {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, nonced_authority_pubkey, 0)],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
nonce_account: None,
nonce_authority: 0,
@@ -735,7 +712,6 @@ fn test_stake_authorize() {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, online_authority_pubkey, 1)],
sign_only: true,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::None(nonce_hash),
nonce_account: Some(nonce_account.pubkey()),
nonce_authority: 0,
@@ -753,7 +729,6 @@ fn test_stake_authorize() {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, online_authority_pubkey, 1)],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_account.pubkey()),
sign_only.blockhash,
@@ -842,7 +817,6 @@ fn test_stake_authorize_with_fee_payer() {
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -859,7 +833,6 @@ fn test_stake_authorize_with_fee_payer() {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, offline_pubkey, 0)],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -879,7 +852,6 @@ fn test_stake_authorize_with_fee_payer() {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, payer_pubkey, 0)],
sign_only: true,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::None(blockhash),
nonce_account: None,
nonce_authority: 0,
@@ -896,7 +868,6 @@ fn test_stake_authorize_with_fee_payer() {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, payer_pubkey, 0)],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
nonce_account: None,
nonce_authority: 0,
@@ -965,7 +936,6 @@ fn test_stake_split() {
lockup: Lockup::default(),
amount: SpendAmount::Some(10 * minimum_stake_balance),
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -1012,7 +982,6 @@ fn test_stake_split() {
stake_account_pubkey,
stake_authority: 0,
sign_only: true,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::None(nonce_hash),
nonce_account: Some(nonce_account.pubkey()),
nonce_authority: 0,
@@ -1031,7 +1000,6 @@ fn test_stake_split() {
stake_account_pubkey,
stake_authority: 0,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_account.pubkey()),
sign_only.blockhash,
@@ -1117,7 +1085,6 @@ fn test_stake_set_lockup() {
lockup,
amount: SpendAmount::Some(10 * minimum_stake_balance),
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
@@ -1143,7 +1110,6 @@ fn test_stake_set_lockup() {
lockup,
custodian: 0,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -1177,7 +1143,6 @@ fn test_stake_set_lockup() {
lockup,
custodian: 0,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -1196,7 +1161,6 @@ fn test_stake_set_lockup() {
lockup,
custodian: 1,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -1227,7 +1191,6 @@ fn test_stake_set_lockup() {
lockup,
custodian: 1,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
@@ -1272,7 +1235,6 @@ fn test_stake_set_lockup() {
lockup,
custodian: 0,
sign_only: true,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::None(nonce_hash),
nonce_account: Some(nonce_account_pubkey),
nonce_authority: 0,
@@ -1289,7 +1251,6 @@ fn test_stake_set_lockup() {
lockup,
custodian: 0,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_account_pubkey),
sign_only.blockhash,
@@ -1334,7 +1295,7 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
let offline_pubkey = config_offline.signers[0].pubkey();
config_offline.json_rpc_url = String::default();
config_offline.command = CliCommand::ClusterVersion;
// Verify that we cannot reach the cluster
// Verfiy that we cannot reach the cluster
process_command(&config_offline).unwrap_err();
request_and_confirm_airdrop(
@@ -1388,7 +1349,6 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: true,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::None(nonce_hash),
nonce_account: Some(nonce_pubkey),
nonce_authority: 0,
@@ -1410,7 +1370,6 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_pubkey),
sign_only.blockhash,
@@ -1444,7 +1403,6 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
withdraw_authority: 0,
custodian: None,
sign_only: true,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::None(nonce_hash),
nonce_account: Some(nonce_pubkey),
nonce_authority: 0,
@@ -1461,7 +1419,6 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
withdraw_authority: 0,
custodian: None,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_pubkey),
sign_only.blockhash,
@@ -1494,7 +1451,6 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: true,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::None(nonce_hash),
nonce_account: Some(nonce_pubkey),
nonce_authority: 0,
@@ -1514,7 +1470,6 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_pubkey),
sign_only.blockhash,

View File

@@ -51,15 +51,11 @@ fn test_transfer() {
to: recipient_pubkey,
from: 0,
sign_only: false,
dump_transaction_message: false,
allow_unfunded_recipient: true,
no_wait: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
process_command(&config).unwrap();
check_recent_balance(49_989, &rpc_client, &sender_pubkey);
@@ -71,15 +67,11 @@ fn test_transfer() {
to: recipient_pubkey,
from: 0,
sign_only: false,
dump_transaction_message: false,
allow_unfunded_recipient: true,
no_wait: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
assert!(process_command(&config).is_err());
check_recent_balance(49_989, &rpc_client, &sender_pubkey);
@@ -103,15 +95,11 @@ fn test_transfer() {
to: recipient_pubkey,
from: 0,
sign_only: true,
dump_transaction_message: false,
allow_unfunded_recipient: true,
no_wait: false,
blockhash_query: BlockhashQuery::None(blockhash),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
offline.output_format = OutputFormat::JsonCompact;
let sign_only_reply = process_command(&offline).unwrap();
@@ -124,15 +112,11 @@ fn test_transfer() {
to: recipient_pubkey,
from: 0,
sign_only: false,
dump_transaction_message: false,
allow_unfunded_recipient: true,
no_wait: false,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
process_command(&config).unwrap();
check_recent_balance(39, &rpc_client, &offline_pubkey);
@@ -170,8 +154,6 @@ fn test_transfer() {
to: recipient_pubkey,
from: 0,
sign_only: false,
dump_transaction_message: false,
allow_unfunded_recipient: true,
no_wait: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_account.pubkey()),
@@ -180,8 +162,6 @@ fn test_transfer() {
nonce_account: Some(nonce_account.pubkey()),
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
process_command(&config).unwrap();
check_recent_balance(49_976 - minimum_nonce_balance, &rpc_client, &sender_pubkey);
@@ -223,15 +203,11 @@ fn test_transfer() {
to: recipient_pubkey,
from: 0,
sign_only: true,
dump_transaction_message: false,
allow_unfunded_recipient: true,
no_wait: false,
blockhash_query: BlockhashQuery::None(nonce_hash),
nonce_account: Some(nonce_account.pubkey()),
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
let sign_only_reply = process_command(&offline).unwrap();
let sign_only = parse_sign_only_reply_string(&sign_only_reply);
@@ -243,8 +219,6 @@ fn test_transfer() {
to: recipient_pubkey,
from: 0,
sign_only: false,
dump_transaction_message: false,
allow_unfunded_recipient: true,
no_wait: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_account.pubkey()),
@@ -253,8 +227,6 @@ fn test_transfer() {
nonce_account: Some(nonce_account.pubkey()),
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
process_command(&config).unwrap();
check_recent_balance(28, &rpc_client, &offline_pubkey);
@@ -313,15 +285,11 @@ fn test_transfer_multisession_signing() {
to: to_pubkey,
from: 1,
sign_only: true,
dump_transaction_message: false,
allow_unfunded_recipient: true,
no_wait: false,
blockhash_query: BlockhashQuery::None(blockhash),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
fee_payer_config.output_format = OutputFormat::JsonCompact;
let sign_only_reply = process_command(&fee_payer_config).unwrap();
@@ -343,15 +311,11 @@ fn test_transfer_multisession_signing() {
to: to_pubkey,
from: 1,
sign_only: true,
dump_transaction_message: false,
allow_unfunded_recipient: true,
no_wait: false,
blockhash_query: BlockhashQuery::None(blockhash),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
from_config.output_format = OutputFormat::JsonCompact;
let sign_only_reply = process_command(&from_config).unwrap();
@@ -370,15 +334,11 @@ fn test_transfer_multisession_signing() {
to: to_pubkey,
from: 1,
sign_only: false,
dump_transaction_message: false,
allow_unfunded_recipient: true,
no_wait: false,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
process_command(&config).unwrap();
@@ -419,122 +379,13 @@ fn test_transfer_all() {
to: recipient_pubkey,
from: 0,
sign_only: false,
dump_transaction_message: false,
allow_unfunded_recipient: true,
no_wait: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
process_command(&config).unwrap();
check_recent_balance(0, &rpc_client, &sender_pubkey);
check_recent_balance(49_999, &rpc_client, &recipient_pubkey);
}
#[test]
fn test_transfer_unfunded_recipient() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let test_validator = TestValidator::with_custom_fees(mint_keypair.pubkey(), 1);
let faucet_addr = run_local_faucet(mint_keypair, None);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
let default_signer = Keypair::new();
let mut config = CliConfig::recent_for_tests();
config.json_rpc_url = test_validator.rpc_url();
config.signers = vec![&default_signer];
let sender_pubkey = config.signers[0].pubkey();
let recipient_pubkey = Pubkey::new(&[1u8; 32]);
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);
check_ready(&rpc_client);
// Plain ole transfer
config.command = CliCommand::Transfer {
amount: SpendAmount::All,
to: recipient_pubkey,
from: 0,
sign_only: false,
dump_transaction_message: false,
allow_unfunded_recipient: false,
no_wait: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
// Expect failure due to unfunded recipient and the lack of the `allow_unfunded_recipient` flag
process_command(&config).unwrap_err();
}
#[test]
fn test_transfer_with_seed() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let test_validator = TestValidator::with_custom_fees(mint_keypair.pubkey(), 1);
let faucet_addr = run_local_faucet(mint_keypair, None);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
let default_signer = Keypair::new();
let mut config = CliConfig::recent_for_tests();
config.json_rpc_url = test_validator.rpc_url();
config.signers = vec![&default_signer];
let sender_pubkey = config.signers[0].pubkey();
let recipient_pubkey = Pubkey::new(&[1u8; 32]);
let derived_address_seed = "seed".to_string();
let derived_address_program_id = solana_stake_program::id();
let derived_address = Pubkey::create_with_seed(
&sender_pubkey,
&derived_address_seed,
&derived_address_program_id,
)
.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);
check_ready(&rpc_client);
// Transfer with seed
config.command = CliCommand::Transfer {
amount: SpendAmount::Some(50_000),
to: recipient_pubkey,
from: 0,
sign_only: false,
dump_transaction_message: false,
allow_unfunded_recipient: true,
no_wait: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: Some(derived_address_seed),
derived_address_program_id: Some(derived_address_program_id),
};
process_command(&config).unwrap();
check_recent_balance(0, &rpc_client, &sender_pubkey);
check_recent_balance(50_000, &rpc_client, &recipient_pubkey);
check_recent_balance(0, &rpc_client, &derived_address);
}

View File

@@ -71,15 +71,11 @@ fn test_vote_authorize_and_withdraw() {
to: vote_account_pubkey,
from: 0,
sign_only: false,
dump_transaction_message: false,
allow_unfunded_recipient: true,
no_wait: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
process_command(&config).unwrap();
let expected_balance = expected_balance + 1_000;

View File

@@ -1,11 +1,10 @@
[package]
name = "solana-client"
version = "1.6.3"
version = "1.5.7"
description = "Solana Client"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-client"
license = "Apache-2.0"
edition = "2018"
@@ -15,30 +14,31 @@ bincode = "1.3.1"
bs58 = "0.3.1"
clap = "2.33.0"
indicatif = "0.15.0"
jsonrpc-core = "17.0.0"
jsonrpc-core = "15.0.0"
log = "0.4.11"
net2 = "0.2.37"
rayon = "1.5.0"
reqwest = { version = "0.11.2", default-features = false, features = ["blocking", "rustls-tls", "json"] }
rayon = "1.4.0"
reqwest = { version = "0.10.8", default-features = false, features = ["blocking", "rustls-tls", "json"] }
semver = "0.11.0"
serde = "1.0.122"
serde = "1.0.112"
serde_derive = "1.0.103"
serde_json = "1.0.56"
solana-account-decoder = { path = "../account-decoder", version = "=1.6.3" }
solana-clap-utils = { path = "../clap-utils", version = "=1.6.3" }
solana-net-utils = { path = "../net-utils", version = "=1.6.3" }
solana-sdk = { path = "../sdk", version = "=1.6.3" }
solana-transaction-status = { path = "../transaction-status", version = "=1.6.3" }
solana-version = { path = "../version", version = "=1.6.3" }
solana-vote-program = { path = "../programs/vote", version = "=1.6.3" }
solana-account-decoder = { path = "../account-decoder", version = "1.5.7" }
solana-clap-utils = { path = "../clap-utils", version = "1.5.7" }
solana-net-utils = { path = "../net-utils", version = "1.5.7" }
solana-sdk = { path = "../sdk", version = "1.5.7" }
solana-transaction-status = { path = "../transaction-status", version = "1.5.7" }
solana-version = { path = "../version", version = "1.5.7" }
solana-vote-program = { path = "../programs/vote", version = "1.5.7" }
thiserror = "1.0"
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.6.3" }
jsonrpc-core = "15.0.0"
jsonrpc-http-server = "15.0.0"
solana-logger = { path = "../logger", version = "1.5.7" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -1,15 +1,12 @@
use {
crate::{nonce_utils, rpc_client::RpcClient},
clap::ArgMatches,
solana_clap_utils::{
input_parsers::{pubkey_of, value_of},
nonce::*,
offline::*,
},
solana_sdk::{
commitment_config::CommitmentConfig, fee_calculator::FeeCalculator, hash::Hash,
pubkey::Pubkey,
},
use crate::{nonce_utils, rpc_client::RpcClient};
use clap::ArgMatches;
use solana_clap_utils::{
input_parsers::{pubkey_of, value_of},
nonce::*,
offline::*,
};
use solana_sdk::{
commitment_config::CommitmentConfig, fee_calculator::FeeCalculator, hash::Hash, pubkey::Pubkey,
};
#[derive(Debug, PartialEq)]

View File

@@ -1,11 +1,9 @@
use {
crate::rpc_request,
solana_sdk::{
signature::SignerError, transaction::TransactionError, transport::TransportError,
},
std::io,
thiserror::Error,
use crate::rpc_request;
use solana_sdk::{
signature::SignerError, transaction::TransactionError, transport::TransportError,
};
use std::io;
use thiserror::Error;
pub use reqwest; // export `reqwest` for clients

View File

@@ -1,15 +1,13 @@
use {
crate::{
client_error::Result,
rpc_custom_error,
rpc_request::{RpcError, RpcRequest, RpcResponseErrorData},
rpc_response::RpcSimulateTransactionResult,
rpc_sender::RpcSender,
},
log::*,
reqwest::{self, header::CONTENT_TYPE, StatusCode},
std::{thread::sleep, time::Duration},
use crate::{
client_error::Result,
rpc_custom_error,
rpc_request::{RpcError, RpcRequest, RpcResponseErrorData},
rpc_response::RpcSimulateTransactionResult,
rpc_sender::RpcSender,
};
use log::*;
use reqwest::{self, header::CONTENT_TYPE, StatusCode};
use std::{thread::sleep, time::Duration};
pub struct HttpSender {
client: reqwest::blocking::Client,
@@ -87,7 +85,7 @@ impl RpcSender for HttpSender {
}
}
},
rpc_custom_error::JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY => {
rpc_custom_error::JSON_RPC_SERVER_ERROR_NODE_UNHEALTHLY => {
match serde_json::from_value::<rpc_custom_error::NodeUnhealthyErrorData>(json["error"]["data"].clone()) {
Ok(rpc_custom_error::NodeUnhealthyErrorData {num_slots_behind}) => RpcResponseErrorData::NodeUnhealthy {num_slots_behind},
Err(_err) => {

View File

@@ -1,4 +1,3 @@
#![allow(clippy::integer_arithmetic)]
#[macro_use]
extern crate serde_derive;

View File

@@ -1,22 +1,20 @@
use {
crate::{
client_error::Result,
rpc_request::RpcRequest,
rpc_response::{Response, RpcResponseContext, RpcVersionInfo},
rpc_sender::RpcSender,
},
serde_json::{json, Number, Value},
solana_sdk::{
epoch_info::EpochInfo,
fee_calculator::{FeeCalculator, FeeRateGovernor},
instruction::InstructionError,
signature::Signature,
transaction::{self, Transaction, TransactionError},
},
solana_transaction_status::{TransactionConfirmationStatus, TransactionStatus},
solana_version::Version,
std::{collections::HashMap, sync::RwLock},
use crate::{
client_error::Result,
rpc_request::RpcRequest,
rpc_response::{Response, RpcResponseContext, RpcVersionInfo},
rpc_sender::RpcSender,
};
use serde_json::{json, Number, Value};
use solana_sdk::{
epoch_info::EpochInfo,
fee_calculator::{FeeCalculator, FeeRateGovernor},
instruction::InstructionError,
signature::Signature,
transaction::{self, Transaction, TransactionError},
};
use solana_transaction_status::{TransactionConfirmationStatus, TransactionStatus};
use solana_version::Version;
use std::{collections::HashMap, sync::RwLock};
pub const PUBKEY: &str = "7RoSF9fUmdphVCpabEoefH81WwrW7orsWonXWqTXkKV8";
pub const SIGNATURE: &str =

View File

@@ -1,16 +1,14 @@
use {
crate::rpc_client::RpcClient,
solana_sdk::{
account::{Account, ReadableAccount},
account_utils::StateMut,
commitment_config::CommitmentConfig,
nonce::{
state::{Data, Versions},
State,
},
pubkey::Pubkey,
system_program,
use crate::rpc_client::RpcClient;
use solana_sdk::{
account::Account,
account_utils::StateMut,
commitment_config::CommitmentConfig,
nonce::{
state::{Data, Versions},
State,
},
pubkey::Pubkey,
system_program,
};
#[derive(Debug, thiserror::Error, PartialEq)]
@@ -54,28 +52,24 @@ pub fn get_account_with_commitment(
})
}
pub fn account_identity_ok<T: ReadableAccount>(account: &T) -> Result<(), Error> {
if account.owner() != &system_program::id() {
pub fn account_identity_ok(account: &Account) -> Result<(), Error> {
if account.owner != system_program::id() {
Err(Error::InvalidAccountOwner)
} else if account.data().is_empty() {
} else if account.data.is_empty() {
Err(Error::UnexpectedDataSize)
} else {
Ok(())
}
}
pub fn state_from_account<T: ReadableAccount + StateMut<Versions>>(
account: &T,
) -> Result<State, Error> {
pub fn state_from_account(account: &Account) -> Result<State, Error> {
account_identity_ok(account)?;
StateMut::<Versions>::state(account)
.map_err(|_| Error::InvalidAccountData)
.map(|v| v.convert_to_current())
}
pub fn data_from_account<T: ReadableAccount + StateMut<Versions>>(
account: &T,
) -> Result<Data, Error> {
pub fn data_from_account(account: &Account) -> Result<Data, Error> {
account_identity_ok(account)?;
state_from_account(account).and_then(|ref s| data_from_state(s).map(|d| d.clone()))
}

View File

@@ -1,14 +1,12 @@
use {
log::*,
solana_sdk::{client::Client, commitment_config::CommitmentConfig, timing::duration_as_s},
std::{
sync::{
atomic::{AtomicBool, Ordering},
Arc, RwLock,
},
thread::sleep,
time::{Duration, Instant},
use log::*;
use solana_sdk::{client::Client, commitment_config::CommitmentConfig, timing::duration_as_s};
use std::{
sync::{
atomic::{AtomicBool, Ordering},
Arc, RwLock,
},
thread::sleep,
time::{Duration, Instant},
};
#[derive(Default)]

View File

@@ -1,31 +1,27 @@
use {
crate::{
rpc_config::{
RpcSignatureSubscribeConfig, RpcTransactionLogsConfig, RpcTransactionLogsFilter,
},
rpc_response::{Response as RpcResponse, RpcLogsResponse, RpcSignatureResult, SlotInfo},
},
log::*,
serde::de::DeserializeOwned,
serde_json::{
json,
value::Value::{Number, Object},
Map, Value,
},
solana_sdk::signature::Signature,
std::{
marker::PhantomData,
sync::{
atomic::{AtomicBool, Ordering},
mpsc::{channel, Receiver},
Arc, RwLock,
},
thread::JoinHandle,
},
thiserror::Error,
tungstenite::{client::AutoStream, connect, Message, WebSocket},
url::{ParseError, Url},
use crate::{
rpc_config::{RpcSignatureSubscribeConfig, RpcTransactionLogsConfig, RpcTransactionLogsFilter},
rpc_response::{Response as RpcResponse, RpcLogsResponse, RpcSignatureResult, SlotInfo},
};
use log::*;
use serde::de::DeserializeOwned;
use serde_json::{
json,
value::Value::{Number, Object},
Map, Value,
};
use solana_sdk::signature::Signature;
use std::{
marker::PhantomData,
sync::{
atomic::{AtomicBool, Ordering},
mpsc::{channel, Receiver},
Arc, RwLock,
},
thread::JoinHandle,
};
use thiserror::Error;
use tungstenite::{client::AutoStream, connect, Message, WebSocket};
use url::{ParseError, Url};
#[derive(Debug, Error)]
pub enum PubsubClientError {
@@ -102,7 +98,7 @@ where
}
pub fn send_unsubscribe(&self) -> Result<(), PubsubClientError> {
let method = format!("{}Unsubscribe", self.operation);
let method = format!("{}Unubscribe", self.operation);
self.socket
.write()
.unwrap()

View File

@@ -1,9 +1,7 @@
use {
crate::{rpc_config::RpcLargestAccountsFilter, rpc_response::RpcAccountBalance},
std::{
collections::HashMap,
time::{Duration, SystemTime},
},
use crate::{rpc_config::RpcLargestAccountsFilter, rpc_response::RpcAccountBalance};
use std::{
collections::HashMap,
time::{Duration, SystemTime},
};
#[derive(Debug, Clone)]

View File

@@ -1,52 +1,50 @@
use {
crate::{
client_error::{ClientError, ClientErrorKind, Result as ClientResult},
http_sender::HttpSender,
mock_sender::{MockSender, Mocks},
rpc_config::RpcAccountInfoConfig,
rpc_config::{
RpcConfirmedBlockConfig, RpcConfirmedTransactionConfig,
RpcGetConfirmedSignaturesForAddress2Config, RpcLargestAccountsConfig,
RpcProgramAccountsConfig, RpcSendTransactionConfig, RpcSimulateTransactionConfig,
RpcStakeConfig, RpcTokenAccountsFilter,
},
rpc_request::{RpcError, RpcRequest, RpcResponseErrorData, TokenAccountsFilter},
rpc_response::*,
rpc_sender::RpcSender,
use crate::{
client_error::{ClientError, ClientErrorKind, Result as ClientResult},
http_sender::HttpSender,
mock_sender::{MockSender, Mocks},
rpc_config::RpcAccountInfoConfig,
rpc_config::{
RpcGetConfirmedSignaturesForAddress2Config, RpcLargestAccountsConfig,
RpcProgramAccountsConfig, RpcSendTransactionConfig, RpcSimulateTransactionConfig,
RpcTokenAccountsFilter,
},
bincode::serialize,
indicatif::{ProgressBar, ProgressStyle},
log::*,
serde_json::{json, Value},
solana_account_decoder::{
parse_token::{TokenAccountType, UiTokenAccount, UiTokenAmount},
UiAccount, UiAccountData, UiAccountEncoding,
},
solana_sdk::{
account::Account,
clock::{Epoch, Slot, UnixTimestamp, DEFAULT_MS_PER_SLOT, MAX_HASH_AGE_IN_SECONDS},
commitment_config::{CommitmentConfig, CommitmentLevel},
epoch_info::EpochInfo,
epoch_schedule::EpochSchedule,
fee_calculator::{FeeCalculator, FeeRateGovernor},
hash::Hash,
pubkey::Pubkey,
signature::Signature,
transaction::{self, uses_durable_nonce, Transaction},
},
solana_transaction_status::{
EncodedConfirmedBlock, EncodedConfirmedTransaction, TransactionStatus, UiConfirmedBlock,
UiTransactionEncoding,
},
solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY,
std::{
cmp::min,
net::SocketAddr,
str::FromStr,
sync::RwLock,
thread::sleep,
time::{Duration, Instant},
rpc_request::{RpcError, RpcRequest, RpcResponseErrorData, TokenAccountsFilter},
rpc_response::*,
rpc_sender::RpcSender,
};
use bincode::serialize;
use indicatif::{ProgressBar, ProgressStyle};
use log::*;
use serde_json::{json, Value};
use solana_account_decoder::{
parse_token::{TokenAccountType, UiTokenAccount, UiTokenAmount},
UiAccount, UiAccountData, UiAccountEncoding,
};
use solana_sdk::{
account::Account,
clock::{
Slot, UnixTimestamp, DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT,
MAX_HASH_AGE_IN_SECONDS,
},
commitment_config::{CommitmentConfig, CommitmentLevel},
epoch_info::EpochInfo,
epoch_schedule::EpochSchedule,
fee_calculator::{FeeCalculator, FeeRateGovernor},
hash::Hash,
pubkey::Pubkey,
signature::Signature,
transaction::{self, uses_durable_nonce, Transaction},
};
use solana_transaction_status::{
EncodedConfirmedBlock, EncodedConfirmedTransaction, TransactionStatus, UiTransactionEncoding,
};
use solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY;
use std::{
cmp::min,
net::SocketAddr,
sync::RwLock,
thread::sleep,
time::{Duration, Instant},
};
pub struct RpcClient {
@@ -128,13 +126,6 @@ impl RpcClient {
Self::new(get_rpc_request_str(addr, false))
}
pub fn new_socket_with_commitment(
addr: SocketAddr,
commitment_config: CommitmentConfig,
) -> Self {
Self::new_with_commitment(get_rpc_request_str(addr, false), commitment_config)
}
pub fn new_socket_with_timeout(addr: SocketAddr, timeout: Duration) -> Self {
let url = get_rpc_request_str(addr, false);
Self::new_with_timeout(url, timeout)
@@ -409,41 +400,6 @@ impl RpcClient {
)
}
pub fn get_slot_leaders(&self, start_slot: Slot, limit: u64) -> ClientResult<Vec<Pubkey>> {
self.send(RpcRequest::GetSlotLeaders, json!([start_slot, limit]))
.and_then(|slot_leaders: Vec<String>| {
slot_leaders
.iter()
.map(|slot_leader| {
Pubkey::from_str(slot_leader).map_err(|err| {
ClientErrorKind::Custom(format!(
"pubkey deserialization failed: {}",
err
))
.into()
})
})
.collect()
})
}
pub fn get_stake_activation(
&self,
stake_account: Pubkey,
epoch: Option<Epoch>,
) -> ClientResult<RpcStakeActivation> {
self.send(
RpcRequest::GetStakeActivation,
json!([
stake_account.to_string(),
RpcStakeConfig {
epoch,
commitment: Some(self.commitment_config),
}
]),
)
}
pub fn supply(&self) -> RpcResult<RpcSupply> {
self.supply_with_commitment(self.commitment_config)
}
@@ -547,14 +503,6 @@ impl RpcClient {
self.send(RpcRequest::GetConfirmedBlock, json!([slot, encoding]))
}
pub fn get_confirmed_block_with_config(
&self,
slot: Slot,
config: RpcConfirmedBlockConfig,
) -> ClientResult<UiConfirmedBlock> {
self.send(RpcRequest::GetConfirmedBlock, json!([slot, config]))
}
pub fn get_confirmed_blocks(
&self,
start_slot: Slot,
@@ -566,24 +514,6 @@ impl RpcClient {
)
}
pub fn get_confirmed_blocks_with_commitment(
&self,
start_slot: Slot,
end_slot: Option<Slot>,
commitment_config: CommitmentConfig,
) -> ClientResult<Vec<Slot>> {
let json = if end_slot.is_some() {
json!([
start_slot,
end_slot,
self.maybe_map_commitment(commitment_config)?
])
} else {
json!([start_slot, self.maybe_map_commitment(commitment_config)?])
};
self.send(RpcRequest::GetConfirmedBlocks, json)
}
pub fn get_confirmed_blocks_with_limit(
&self,
start_slot: Slot,
@@ -595,22 +525,6 @@ impl RpcClient {
)
}
pub fn get_confirmed_blocks_with_limit_and_commitment(
&self,
start_slot: Slot,
limit: usize,
commitment_config: CommitmentConfig,
) -> ClientResult<Vec<Slot>> {
self.send(
RpcRequest::GetConfirmedBlocksWithLimit,
json!([
start_slot,
limit,
self.maybe_map_commitment(commitment_config)?
]),
)
}
pub fn get_confirmed_signatures_for_address(
&self,
address: &Pubkey,
@@ -652,7 +566,6 @@ impl RpcClient {
before: config.before.map(|signature| signature.to_string()),
until: config.until.map(|signature| signature.to_string()),
limit: config.limit,
commitment: config.commitment,
};
let result: Vec<RpcConfirmedTransactionStatusWithSignature> = self.send(
@@ -674,17 +587,6 @@ impl RpcClient {
)
}
pub fn get_confirmed_transaction_with_config(
&self,
signature: &Signature,
config: RpcConfirmedTransactionConfig,
) -> ClientResult<EncodedConfirmedTransaction> {
self.send(
RpcRequest::GetConfirmedTransaction,
json!([signature.to_string(), config]),
)
}
pub fn get_block_time(&self, slot: Slot) -> ClientResult<UnixTimestamp> {
let request = RpcRequest::GetBlockTime;
let response = self.sender.send(request, json!([slot]));
@@ -738,13 +640,6 @@ impl RpcClient {
self.send(RpcRequest::GetEpochSchedule, Value::Null)
}
pub fn get_recent_performance_samples(
&self,
limit: Option<usize>,
) -> ClientResult<Vec<RpcPerfSample>> {
self.send(RpcRequest::GetRecentPerformanceSamples, json!([limit]))
}
pub fn get_identity(&self) -> ClientResult<Pubkey> {
let rpc_identity: RpcIdentity = self.send(RpcRequest::GetIdentity, Value::Null)?;
@@ -870,14 +765,6 @@ impl RpcClient {
})?
}
pub fn get_max_retransmit_slot(&self) -> ClientResult<Slot> {
self.send(RpcRequest::GetMaxRetransmitSlot, Value::Null)
}
pub fn get_max_shred_insert_slot(&self) -> ClientResult<Slot> {
self.send(RpcRequest::GetMaxShredInsertSlot, Value::Null)
}
pub fn get_multiple_accounts(&self, pubkeys: &[Pubkey]) -> ClientResult<Vec<Option<Account>>> {
Ok(self
.get_multiple_accounts_with_commitment(pubkeys, self.commitment_config)?
@@ -1112,7 +999,9 @@ impl RpcClient {
debug!("Got same blockhash ({:?}), will retry...", blockhash);
// Retry ~twice during a slot
sleep(Duration::from_millis(DEFAULT_MS_PER_SLOT / 2));
sleep(Duration::from_millis(
500 * DEFAULT_TICKS_PER_SLOT / DEFAULT_TICKS_PER_SECOND,
));
num_retries += 1;
}
Err(RpcError::ForUser(format!(
@@ -1614,6 +1503,10 @@ impl RpcClient {
}
}
pub fn validator_exit(&self) -> ClientResult<bool> {
self.send(RpcRequest::ValidatorExit, Value::Null)
}
pub fn send<T>(&self, request: RpcRequest, params: Value) -> ClientResult<T>
where
T: serde::de::DeserializeOwned,
@@ -1633,7 +1526,6 @@ pub struct GetConfirmedSignaturesForAddress2Config {
pub before: Option<Signature>,
pub until: Option<Signature>,
pub limit: Option<usize>,
pub commitment: Option<CommitmentConfig>,
}
fn new_spinner_progress_bar() -> ProgressBar {
@@ -1682,7 +1574,7 @@ mod tests {
use super::*;
use crate::{client_error::ClientErrorKind, mock_sender::PUBKEY};
use assert_matches::assert_matches;
use jsonrpc_core::{futures::prelude::*, Error, IoHandler, Params};
use jsonrpc_core::{Error, IoHandler, Params};
use jsonrpc_http_server::{AccessControlAllowOrigin, DomainsValidation, ServerBuilder};
use serde_json::Number;
use solana_sdk::{
@@ -1699,14 +1591,14 @@ mod tests {
let mut io = IoHandler::default();
// Successful request
io.add_method("getBalance", |_params: Params| {
future::ok(Value::Number(Number::from(50)))
Ok(Value::Number(Number::from(50)))
});
// Failed request
io.add_method("getRecentBlockhash", |params: Params| {
if params != Params::None {
future::err(Error::invalid_request())
Err(Error::invalid_request())
} else {
future::ok(Value::String(
Ok(Value::String(
"deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx".to_string(),
))
}

View File

@@ -1,12 +1,10 @@
use {
crate::rpc_filter::RpcFilterType,
solana_account_decoder::{UiAccountEncoding, UiDataSliceConfig},
solana_sdk::{
clock::{Epoch, Slot},
commitment_config::{CommitmentConfig, CommitmentLevel},
},
solana_transaction_status::{TransactionDetails, UiTransactionEncoding},
use crate::rpc_filter::RpcFilterType;
use solana_account_decoder::{UiAccountEncoding, UiDataSliceConfig};
use solana_sdk::{
clock::Epoch,
commitment_config::{CommitmentConfig, CommitmentLevel},
};
use solana_transaction_status::UiTransactionEncoding;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
@@ -109,87 +107,4 @@ pub struct RpcGetConfirmedSignaturesForAddress2Config {
pub before: Option<String>, // Signature as base-58 string
pub until: Option<String>, // Signature as base-58 string
pub limit: Option<usize>,
#[serde(flatten)]
pub commitment: Option<CommitmentConfig>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RpcEncodingConfigWrapper<T> {
Deprecated(Option<UiTransactionEncoding>),
Current(Option<T>),
}
impl<T: EncodingConfig + Default + Copy> RpcEncodingConfigWrapper<T> {
pub fn convert_to_current(&self) -> T {
match self {
RpcEncodingConfigWrapper::Deprecated(encoding) => T::new_with_encoding(encoding),
RpcEncodingConfigWrapper::Current(config) => config.unwrap_or_default(),
}
}
}
pub trait EncodingConfig {
fn new_with_encoding(encoding: &Option<UiTransactionEncoding>) -> Self;
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RpcConfirmedBlockConfig {
pub encoding: Option<UiTransactionEncoding>,
pub transaction_details: Option<TransactionDetails>,
pub rewards: Option<bool>,
#[serde(flatten)]
pub commitment: Option<CommitmentConfig>,
}
impl EncodingConfig for RpcConfirmedBlockConfig {
fn new_with_encoding(encoding: &Option<UiTransactionEncoding>) -> Self {
Self {
encoding: *encoding,
..Self::default()
}
}
}
impl RpcConfirmedBlockConfig {
pub fn rewards_only() -> Self {
Self {
transaction_details: Some(TransactionDetails::None),
..Self::default()
}
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RpcConfirmedTransactionConfig {
pub encoding: Option<UiTransactionEncoding>,
#[serde(flatten)]
pub commitment: Option<CommitmentConfig>,
}
impl EncodingConfig for RpcConfirmedTransactionConfig {
fn new_with_encoding(encoding: &Option<UiTransactionEncoding>) -> Self {
Self {
encoding: *encoding,
..Self::default()
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RpcConfirmedBlocksConfigWrapper {
EndSlotOnly(Option<Slot>),
CommitmentOnly(Option<CommitmentConfig>),
}
impl RpcConfirmedBlocksConfigWrapper {
pub fn unzip(&self) -> (Option<Slot>, Option<CommitmentConfig>) {
match &self {
RpcConfirmedBlocksConfigWrapper::EndSlotOnly(end_slot) => (*end_slot, None),
RpcConfirmedBlocksConfigWrapper::CommitmentOnly(commitment) => (None, *commitment),
}
}
}

View File

@@ -1,16 +1,14 @@
//! Implementation defined RPC server errors
use {
crate::rpc_response::RpcSimulateTransactionResult,
jsonrpc_core::{Error, ErrorCode},
solana_sdk::clock::Slot,
};
use crate::rpc_response::RpcSimulateTransactionResult;
use jsonrpc_core::{Error, ErrorCode};
use solana_sdk::clock::Slot;
pub const JSON_RPC_SERVER_ERROR_BLOCK_CLEANED_UP: i64 = -32001;
pub const JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE: i64 = -32002;
pub const JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE: i64 = -32003;
pub const JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE: i64 = -32004;
pub const JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY: i64 = -32005;
pub const JSON_RPC_SERVER_ERROR_NODE_UNHEALTHLY: i64 = -32005;
pub const JSON_RPC_SERVER_ERROR_TRANSACTION_PRECOMPILE_VERIFICATION_FAILURE: i64 = -32006;
pub const JSON_RPC_SERVER_ERROR_SLOT_SKIPPED: i64 = -32007;
pub const JSON_RPC_SERVER_ERROR_NO_SNAPSHOT: i64 = -32008;
@@ -82,7 +80,7 @@ impl From<RpcCustomError> for Error {
data: None,
},
RpcCustomError::NodeUnhealthy { num_slots_behind } => Self {
code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY),
code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_NODE_UNHEALTHLY),
message: if let Some(num_slots_behind) = num_slots_behind {
format!("Node is behind by {} slots", num_slots_behind)
} else {

View File

@@ -16,15 +16,10 @@ impl RpcFilterType {
match encoding {
MemcmpEncoding::Binary => {
let MemcmpEncodedBytes::Binary(bytes) = &compare.bytes;
if bytes.len() > 128 {
Err(RpcFilterError::Base58DataTooLarge)
} else {
bs58::decode(&bytes)
.into_vec()
.map(|_| ())
.map_err(|e| e.into())
}
bs58::decode(&bytes)
.into_vec()
.map(|_| ())
.map_err(|e| e.into())
}
}
}
@@ -32,12 +27,10 @@ impl RpcFilterType {
}
}
#[derive(Error, PartialEq, Debug)]
#[derive(Error, Debug)]
pub enum RpcFilterError {
#[error("bs58 decode error")]
DecodeError(#[from] bs58::decode::Error),
#[error("encoded binary (base 58) data should be less than 129 bytes")]
Base58DataTooLarge,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
@@ -147,36 +140,4 @@ mod tests {
}
.bytes_match(&data));
}
#[test]
fn test_verify_memcmp() {
let base58_bytes = "\
1111111111111111111111111111111111111111111111111111111111111111\
1111111111111111111111111111111111111111111111111111111111111111";
assert_eq!(base58_bytes.len(), 128);
assert_eq!(
RpcFilterType::Memcmp(Memcmp {
offset: 0,
bytes: MemcmpEncodedBytes::Binary(base58_bytes.to_string()),
encoding: None,
})
.verify(),
Ok(())
);
let base58_bytes = "\
1111111111111111111111111111111111111111111111111111111111111111\
1111111111111111111111111111111111111111111111111111111111111111\
1";
assert_eq!(base58_bytes.len(), 129);
assert_eq!(
RpcFilterType::Memcmp(Memcmp {
offset: 0,
bytes: MemcmpEncodedBytes::Binary(base58_bytes.to_string()),
encoding: None,
})
.verify(),
Err(RpcFilterError::Base58DataTooLarge)
);
}
}

View File

@@ -1,14 +1,13 @@
use {
crate::rpc_response::RpcSimulateTransactionResult,
serde_json::{json, Value},
solana_sdk::{clock::Slot, pubkey::Pubkey},
std::fmt,
thiserror::Error,
};
use crate::rpc_response::RpcSimulateTransactionResult;
use serde_json::{json, Value};
use solana_sdk::{clock::Slot, pubkey::Pubkey};
use std::fmt;
use thiserror::Error;
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum RpcRequest {
DeregisterNode,
ValidatorExit,
GetAccountInfo,
GetBalance,
GetBlockTime,
@@ -32,22 +31,17 @@ pub enum RpcRequest {
GetInflationRate,
GetLargestAccounts,
GetLeaderSchedule,
GetMaxRetransmitSlot,
GetMaxShredInsertSlot,
GetMinimumBalanceForRentExemption,
GetMultipleAccounts,
GetProgramAccounts,
GetRecentBlockhash,
GetRecentPerformanceSamples,
GetSnapshotSlot,
GetSignatureStatuses,
GetSlot,
GetSlotLeader,
GetSlotLeaders,
GetStorageTurn,
GetStorageTurnRate,
GetSlotsPerSegment,
GetStakeActivation,
GetStoragePubkeysForSlot,
GetSupply,
GetTokenAccountBalance,
@@ -70,6 +64,7 @@ impl fmt::Display for RpcRequest {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let method = match self {
RpcRequest::DeregisterNode => "deregisterNode",
RpcRequest::ValidatorExit => "validatorExit",
RpcRequest::GetAccountInfo => "getAccountInfo",
RpcRequest::GetBalance => "getBalance",
RpcRequest::GetBlockTime => "getBlockTime",
@@ -93,19 +88,14 @@ impl fmt::Display for RpcRequest {
RpcRequest::GetInflationRate => "getInflationRate",
RpcRequest::GetLargestAccounts => "getLargestAccounts",
RpcRequest::GetLeaderSchedule => "getLeaderSchedule",
RpcRequest::GetMaxRetransmitSlot => "getMaxRetransmitSlot",
RpcRequest::GetMaxShredInsertSlot => "getMaxShredInsertSlot",
RpcRequest::GetMinimumBalanceForRentExemption => "getMinimumBalanceForRentExemption",
RpcRequest::GetMultipleAccounts => "getMultipleAccounts",
RpcRequest::GetProgramAccounts => "getProgramAccounts",
RpcRequest::GetRecentBlockhash => "getRecentBlockhash",
RpcRequest::GetRecentPerformanceSamples => "getRecentPerformanceSamples",
RpcRequest::GetSnapshotSlot => "getSnapshotSlot",
RpcRequest::GetSignatureStatuses => "getSignatureStatuses",
RpcRequest::GetSlot => "getSlot",
RpcRequest::GetSlotLeader => "getSlotLeader",
RpcRequest::GetSlotLeaders => "getSlotLeaders",
RpcRequest::GetStakeActivation => "getStakeActivation",
RpcRequest::GetStorageTurn => "getStorageTurn",
RpcRequest::GetStorageTurnRate => "getStorageTurnRate",
RpcRequest::GetSlotsPerSegment => "getSlotsPerSegment",
@@ -137,8 +127,6 @@ pub const MAX_GET_CONFIRMED_BLOCKS_RANGE: u64 = 500_000;
pub const MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT: usize = 1_000;
pub const MAX_MULTIPLE_ACCOUNTS: usize = 100;
pub const NUM_LARGEST_ACCOUNTS: usize = 20;
pub const MAX_GET_PROGRAM_ACCOUNT_FILTERS: usize = 4;
pub const MAX_GET_SLOT_LEADERS: usize = 5000;
// Validators that are this number of slots behind are considered delinquent
pub const DELINQUENT_VALIDATOR_SLOT_DISTANCE: u64 = 128;

View File

@@ -1,17 +1,13 @@
use {
crate::client_error,
solana_account_decoder::{parse_token::UiTokenAmount, UiAccount},
solana_sdk::{
clock::{Epoch, Slot, UnixTimestamp},
fee_calculator::{FeeCalculator, FeeRateGovernor},
inflation::Inflation,
transaction::{Result, TransactionError},
},
solana_transaction_status::{
ConfirmedTransactionStatusWithSignature, TransactionConfirmationStatus,
},
std::{collections::HashMap, fmt, net::SocketAddr},
use crate::client_error;
use solana_account_decoder::{parse_token::UiTokenAmount, UiAccount};
use solana_sdk::{
clock::{Epoch, Slot, UnixTimestamp},
fee_calculator::{FeeCalculator, FeeRateGovernor},
inflation::Inflation,
transaction::{Result, TransactionError},
};
use solana_transaction_status::ConfirmedTransactionStatusWithSignature;
use std::{collections::HashMap, fmt, net::SocketAddr};
pub type RpcResult<T> = client_error::Result<Response<T>>;
@@ -105,65 +101,6 @@ pub struct SlotInfo {
pub root: Slot,
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct SlotTransactionStats {
pub num_transaction_entries: u64,
pub num_successful_transactions: u64,
pub num_failed_transactions: u64,
pub max_transactions_per_entry: u64,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase", tag = "type")]
pub enum SlotUpdate {
FirstShredReceived {
slot: Slot,
timestamp: u64,
},
Completed {
slot: Slot,
timestamp: u64,
},
CreatedBank {
slot: Slot,
parent: Slot,
timestamp: u64,
},
Frozen {
slot: Slot,
timestamp: u64,
stats: SlotTransactionStats,
},
Dead {
slot: Slot,
timestamp: u64,
err: String,
},
OptimisticConfirmation {
slot: Slot,
timestamp: u64,
},
Root {
slot: Slot,
timestamp: u64,
},
}
impl SlotUpdate {
pub fn slot(&self) -> Slot {
match self {
Self::FirstShredReceived { slot, .. } => *slot,
Self::Completed { slot, .. } => *slot,
Self::CreatedBank { slot, .. } => *slot,
Self::Frozen { slot, .. } => *slot,
Self::Dead { slot, .. } => *slot,
Self::OptimisticConfirmation { slot, .. } => *slot,
Self::Root { slot, .. } => *slot,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase", untagged)]
pub enum RpcSignatureResult {
@@ -317,7 +254,7 @@ pub struct RpcSupply {
pub non_circulating_accounts: Vec<String>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub enum StakeActivationState {
Activating,
@@ -350,7 +287,6 @@ pub struct RpcConfirmedTransactionStatusWithSignature {
pub err: Option<TransactionError>,
pub memo: Option<String>,
pub block_time: Option<UnixTimestamp>,
pub confirmation_status: Option<TransactionConfirmationStatus>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
@@ -377,7 +313,6 @@ impl From<ConfirmedTransactionStatusWithSignature> for RpcConfirmedTransactionSt
err,
memo,
block_time,
confirmation_status: None,
}
}
}

View File

@@ -3,38 +3,36 @@
//! messages to the network directly. The binary encoding of its messages are
//! unstable and may change in future releases.
use {
crate::{rpc_client::RpcClient, rpc_config::RpcProgramAccountsConfig, rpc_response::Response},
bincode::{serialize_into, serialized_size},
log::*,
solana_sdk::{
account::Account,
client::{AsyncClient, Client, SyncClient},
clock::{Slot, MAX_PROCESSING_AGE},
commitment_config::CommitmentConfig,
epoch_info::EpochInfo,
fee_calculator::{FeeCalculator, FeeRateGovernor},
hash::Hash,
instruction::Instruction,
message::Message,
packet::PACKET_DATA_SIZE,
pubkey::Pubkey,
signature::{Keypair, Signature, Signer},
signers::Signers,
system_instruction,
timing::duration_as_ms,
transaction::{self, Transaction},
transport::Result as TransportResult,
},
std::{
io,
net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket},
sync::{
atomic::{AtomicBool, AtomicUsize, Ordering},
RwLock,
},
time::{Duration, Instant},
use crate::{rpc_client::RpcClient, rpc_config::RpcProgramAccountsConfig, rpc_response::Response};
use bincode::{serialize_into, serialized_size};
use log::*;
use solana_sdk::{
account::Account,
client::{AsyncClient, Client, SyncClient},
clock::{Slot, MAX_PROCESSING_AGE},
commitment_config::CommitmentConfig,
epoch_info::EpochInfo,
fee_calculator::{FeeCalculator, FeeRateGovernor},
hash::Hash,
instruction::Instruction,
message::Message,
packet::PACKET_DATA_SIZE,
pubkey::Pubkey,
signature::{Keypair, Signature, Signer},
signers::Signers,
system_instruction,
timing::duration_as_ms,
transaction::{self, Transaction},
transport::Result as TransportResult,
};
use std::{
io,
net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket},
sync::{
atomic::{AtomicBool, AtomicUsize, Ordering},
RwLock,
},
time::{Duration, Instant},
};
struct ClientOptimizer {
@@ -311,6 +309,10 @@ impl ThinClient {
.map_err(|e| e.into())
}
pub fn validator_exit(&self) -> TransportResult<bool> {
self.rpc_client().validator_exit().map_err(|e| e.into())
}
pub fn get_num_blocks_since_signature_confirmation(
&mut self,
sig: &Signature,

View File

@@ -1,9 +1,9 @@
[package]
name = "solana-core"
description = "Blockchain, Rebuilt for Scale"
version = "1.6.3"
version = "1.5.7"
documentation = "https://docs.rs/solana"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-core"
readme = "../README.md"
repository = "https://github.com/solana-labs/solana"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
@@ -23,18 +23,17 @@ byteorder = "1.3.4"
chrono = { version = "0.4.11", features = ["serde"] }
core_affinity = "0.5.10"
crossbeam-channel = "0.4"
ed25519-dalek = "=1.0.1"
fs_extra = "1.2.0"
ed25519-dalek = "=1.0.0-pre.4"
fs_extra = "1.1.0"
flate2 = "1.0"
indexmap = { version = "1.5", features = ["rayon"] }
itertools = "0.9.0"
jsonrpc-core = "17.0.0"
jsonrpc-core-client = { version = "17.0.0", features = ["ipc", "ws"] }
jsonrpc-derive = "17.0.0"
jsonrpc-http-server = "17.0.0"
jsonrpc-pubsub = "17.0.0"
jsonrpc-ws-server = "17.0.0"
libc = "0.2.81"
jsonrpc-core = "15.0.0"
jsonrpc-core-client = { version = "15.0.0", features = ["ws"] }
jsonrpc-derive = "15.0.0"
jsonrpc-http-server = "15.0.0"
jsonrpc-pubsub = "15.0.0"
jsonrpc-ws-server = "15.0.0"
log = "0.4.11"
lru = "0.6.1"
miow = "0.2.2"
@@ -42,55 +41,56 @@ net2 = "0.2.37"
num-traits = "0.2"
rand = "0.7.0"
rand_chacha = "0.2.2"
rand_core = "0.6.2"
raptorq = "1.4.2"
rayon = "1.5.0"
rayon = "1.4.1"
regex = "1.3.9"
retain_mut = "0.1.2"
rustversion = "1.0.4"
serde = "1.0.122"
serde = "1.0.112"
serde_bytes = "0.11"
serde_derive = "1.0.103"
serde_json = "1.0.56"
solana-account-decoder = { path = "../account-decoder", version = "=1.6.3" }
solana-banks-server = { path = "../banks-server", version = "=1.6.3" }
solana-clap-utils = { path = "../clap-utils", version = "=1.6.3" }
solana-client = { path = "../client", version = "=1.6.3" }
solana-faucet = { path = "../faucet", version = "=1.6.3" }
solana-ledger = { path = "../ledger", version = "=1.6.3" }
solana-logger = { path = "../logger", version = "=1.6.3" }
solana-merkle-tree = { path = "../merkle-tree", version = "=1.6.3" }
solana-metrics = { path = "../metrics", version = "=1.6.3" }
solana-measure = { path = "../measure", version = "=1.6.3" }
solana-net-utils = { path = "../net-utils", version = "=1.6.3" }
solana-perf = { path = "../perf", version = "=1.6.3" }
solana-program-test = { path = "../program-test", version = "=1.6.3" }
solana-runtime = { path = "../runtime", version = "=1.6.3" }
solana-sdk = { path = "../sdk", version = "=1.6.3" }
solana-frozen-abi = { path = "../frozen-abi", version = "=1.6.3" }
solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "=1.6.3" }
solana-stake-program = { path = "../programs/stake", version = "=1.6.3" }
solana-storage-bigtable = { path = "../storage-bigtable", version = "=1.6.3" }
solana-streamer = { path = "../streamer", version = "=1.6.3" }
solana-sys-tuner = { path = "../sys-tuner", version = "=1.6.3" }
solana-transaction-status = { path = "../transaction-status", version = "=1.6.3" }
solana-version = { path = "../version", version = "=1.6.3" }
solana-vote-program = { path = "../programs/vote", version = "=1.6.3" }
spl-token-v2-0 = { package = "spl-token", version = "=3.1.0", features = ["no-entrypoint"] }
solana-account-decoder = { path = "../account-decoder", version = "1.5.7" }
solana-banks-server = { path = "../banks-server", version = "1.5.7" }
solana-clap-utils = { path = "../clap-utils", version = "1.5.7" }
solana-client = { path = "../client", version = "1.5.7" }
solana-faucet = { path = "../faucet", version = "1.5.7" }
solana-ledger = { path = "../ledger", version = "1.5.7" }
solana-logger = { path = "../logger", version = "1.5.7" }
solana-merkle-tree = { path = "../merkle-tree", version = "1.5.7" }
solana-metrics = { path = "../metrics", version = "1.5.7" }
solana-measure = { path = "../measure", version = "1.5.7" }
solana-net-utils = { path = "../net-utils", version = "1.5.7" }
solana-perf = { path = "../perf", version = "1.5.7" }
solana-program-test = { path = "../program-test", version = "1.5.7" }
solana-runtime = { path = "../runtime", version = "1.5.7" }
solana-sdk = { path = "../sdk", version = "1.5.7" }
solana-frozen-abi = { path = "../frozen-abi", version = "1.5.7" }
solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "1.5.7" }
solana-stake-program = { path = "../programs/stake", version = "1.5.7" }
solana-storage-bigtable = { path = "../storage-bigtable", version = "1.5.7" }
solana-streamer = { path = "../streamer", version = "1.5.7" }
solana-sys-tuner = { path = "../sys-tuner", version = "1.5.7" }
solana-transaction-status = { path = "../transaction-status", version = "1.5.7" }
solana-version = { path = "../version", version = "1.5.7" }
solana-vote-program = { path = "../programs/vote", version = "1.5.7" }
spl-token-v2-0 = { package = "spl-token", version = "=3.0.1", features = ["no-entrypoint"] }
tempfile = "3.1.0"
thiserror = "1.0"
tokio = { version = "1.1", features = ["full"] }
tokio_02 = { version = "0.2", package = "tokio", features = ["full"] }
tokio-util = { version = "0.3", features = ["codec"] } # This crate needs to stay in sync with tokio_02, until that dependency can be removed
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.6.3" }
tokio = { version = "0.2", features = ["full"] }
tokio_01 = { version = "0.1", package = "tokio" }
tokio_01_bytes = { version = "0.4.7", package = "bytes" }
tokio_fs_01 = { version = "0.1", package = "tokio-fs" }
tokio_io_01 = { version = "0.1", package = "tokio-io" }
tokio_codec_01 = { version = "0.1", package = "tokio-codec" }
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.5.7" }
trees = "0.2.1"
[dev-dependencies]
matches = "0.1.6"
num_cpus = "1.13.0"
reqwest = { version = "0.11.2", default-features = false, features = ["blocking", "rustls-tls", "json"] }
reqwest = { version = "0.10.8", default-features = false, features = ["blocking", "rustls-tls", "json"] }
serial_test = "0.4.0"
symlink = "0.1.0"
serial_test_derive = "0.4.0"
systemstat = "0.1.5"
[build-dependencies]

View File

@@ -1,4 +1,3 @@
#![allow(clippy::integer_arithmetic)]
#![feature(test)]
extern crate test;
@@ -29,7 +28,6 @@ use solana_sdk::system_instruction;
use solana_sdk::system_transaction;
use solana_sdk::timing::{duration_as_us, timestamp};
use solana_sdk::transaction::Transaction;
use std::collections::VecDeque;
use std::sync::atomic::Ordering;
use std::sync::mpsc::Receiver;
use std::sync::Arc;
@@ -66,16 +64,14 @@ fn bench_consume_buffered(bencher: &mut Bencher) {
let (exit, poh_recorder, poh_service, _signal_receiver) =
create_test_recorder(&bank, &blockstore, None);
let recorder = poh_recorder.lock().unwrap().recorder();
let tx = test_tx();
let len = 4096;
let chunk_size = 1024;
let batches = to_packets_chunked(&vec![tx; len], chunk_size);
let mut packets = VecDeque::new();
let mut packets = vec![];
for batch in batches {
let batch_len = batch.packets.len();
packets.push_back((batch, vec![0usize; batch_len], false));
packets.push((batch, vec![0usize; batch_len]));
}
let (s, _r) = unbounded();
// This tests the performance of buffering packets.
@@ -83,14 +79,11 @@ fn bench_consume_buffered(bencher: &mut Bencher) {
bencher.iter(move || {
let _ignored = BankingStage::consume_buffered_packets(
&my_pubkey,
std::u128::MAX,
&poh_recorder,
&mut packets,
10_000,
None,
&s,
None::<Box<dyn Fn()>>,
None,
&recorder,
);
});
@@ -158,9 +151,6 @@ fn bench_banking(bencher: &mut Bencher, tx_type: TransactionType) {
let (verified_sender, verified_receiver) = unbounded();
let (vote_sender, vote_receiver) = unbounded();
let mut bank = Bank::new(&genesis_config);
// Allow arbitrary transaction processing time for the purposes of this bench
bank.ns_per_slot = std::u128::MAX;
let bank = Arc::new(Bank::new(&genesis_config));
debug!("threads: {} txs: {}", num_threads, txes);
@@ -302,7 +292,7 @@ fn simulate_process_entries(
hash: next_hash(&bank.last_blockhash(), 1, &tx_vector),
transactions: tx_vector,
};
process_entries(&bank, &mut [entry], randomize_txs, None, None).unwrap();
process_entries(&bank, &[entry], randomize_txs, None, None).unwrap();
}
#[allow(clippy::same_item_push)]

View File

@@ -1,4 +1,3 @@
#![allow(clippy::integer_arithmetic)]
#![feature(test)]
extern crate solana_ledger;
extern crate test;

View File

@@ -3,7 +3,7 @@
#![feature(test)]
extern crate test;
use solana_core::poh_service::DEFAULT_HASHES_PER_BATCH;
use solana_core::poh_service::NUM_HASHES_PER_BATCH;
use solana_ledger::poh::Poh;
use solana_sdk::hash::Hash;
use std::sync::atomic::{AtomicBool, Ordering};
@@ -43,7 +43,7 @@ fn bench_arc_mutex_poh_batched_hash(bencher: &mut Bencher) {
bencher.iter(|| {
// NOTE: This block attempts to look as close as possible to `PohService::tick_producer()`
loop {
if poh.lock().unwrap().hash(DEFAULT_HASHES_PER_BATCH) {
if poh.lock().unwrap().hash(NUM_HASHES_PER_BATCH) {
poh.lock().unwrap().tick().unwrap();
if exit.load(Ordering::Relaxed) {
break;
@@ -58,6 +58,6 @@ fn bench_arc_mutex_poh_batched_hash(bencher: &mut Bencher) {
fn bench_poh_lock_time_per_batch(bencher: &mut Bencher) {
let mut poh = Poh::new(Hash::default(), None);
bencher.iter(|| {
poh.hash(DEFAULT_HASHES_PER_BATCH);
poh.hash(NUM_HASHES_PER_BATCH);
})
}

View File

@@ -6,7 +6,6 @@ extern crate test;
use log::*;
use solana_core::cluster_info::{ClusterInfo, Node};
use solana_core::contact_info::ContactInfo;
use solana_core::max_slots::MaxSlots;
use solana_core::retransmit_stage::retransmitter;
use solana_ledger::entry::Entry;
use solana_ledger::genesis_utils::{create_genesis_config, GenesisConfigInfo};
@@ -93,8 +92,6 @@ fn bench_retransmitter(bencher: &mut Bencher) {
&leader_schedule_cache,
cluster_info,
packet_receiver,
&Arc::new(MaxSlots::default()),
None,
);
let mut index = 0;

View File

@@ -1,4 +1,3 @@
#![allow(clippy::integer_arithmetic)]
#![feature(test)]
extern crate test;
@@ -42,13 +41,7 @@ fn make_shreds(num_shreds: usize) -> Vec<Shred> {
let shredder =
Shredder::new(1, 0, RECOMMENDED_FEC_RATE, Arc::new(Keypair::new()), 0, 0).unwrap();
let data_shreds = shredder
.entries_to_data_shreds(
&entries,
true, // is_last_in_slot
0, // next_shred_index
0, // fec_set_offset
&mut ProcessShredsStats::default(),
)
.entries_to_data_shreds(&entries, true, 0, &mut ProcessShredsStats::default())
.0;
assert!(data_shreds.len() >= num_shreds);
data_shreds
@@ -133,8 +126,10 @@ fn bench_shredder_coding(bencher: &mut Bencher) {
let data_shreds = make_shreds(symbol_count);
bencher.iter(|| {
Shredder::generate_coding_shreds(
0,
RECOMMENDED_FEC_RATE,
&data_shreds[..symbol_count],
0,
symbol_count,
)
.len();
@@ -146,8 +141,10 @@ fn bench_shredder_decoding(bencher: &mut Bencher) {
let symbol_count = MAX_DATA_SHREDS_PER_FEC_BLOCK as usize;
let data_shreds = make_shreds(symbol_count);
let coding_shreds = Shredder::generate_coding_shreds(
0,
RECOMMENDED_FEC_RATE,
&data_shreds[..symbol_count],
0,
symbol_count,
);
bencher.iter(|| {

View File

@@ -1,154 +0,0 @@
use crate::{
consensus::{ComputedBankState, Tower},
fork_choice::ForkChoice,
progress_map::{ForkStats, ProgressMap},
};
use solana_runtime::{bank::Bank, bank_forks::BankForks};
use solana_sdk::{clock::Slot, timing};
use std::time::Instant;
use std::{
collections::{HashMap, HashSet},
sync::{Arc, RwLock},
};
#[derive(Default)]
pub struct BankWeightForkChoice {}
impl ForkChoice for BankWeightForkChoice {
fn compute_bank_stats(
&mut self,
bank: &Bank,
_tower: &Tower,
progress: &mut ProgressMap,
computed_bank_state: &ComputedBankState,
) {
let bank_slot = bank.slot();
// Only time progress map should be missing a bank slot
// is if this node was the leader for this slot as those banks
// are not replayed in replay_active_banks()
let parent_weight = bank
.parent()
.and_then(|b| progress.get(&b.slot()))
.map(|x| x.fork_stats.fork_weight)
.unwrap_or(0);
let stats = progress
.get_fork_stats_mut(bank_slot)
.expect("All frozen banks must exist in the Progress map");
let ComputedBankState { bank_weight, .. } = computed_bank_state;
stats.weight = *bank_weight;
stats.fork_weight = stats.weight + parent_weight;
}
// Returns:
// 1) The heaviest overall bank
// 2) The heaviest bank on the same fork as the last vote (doesn't require a
// switching proof to vote for)
fn select_forks(
&self,
frozen_banks: &[Arc<Bank>],
tower: &Tower,
progress: &ProgressMap,
ancestors: &HashMap<u64, HashSet<u64>>,
_bank_forks: &RwLock<BankForks>,
) -> (Arc<Bank>, Option<Arc<Bank>>) {
let tower_start = Instant::now();
assert!(!frozen_banks.is_empty());
let num_frozen_banks = frozen_banks.len();
trace!("frozen_banks {}", frozen_banks.len());
let num_old_banks = frozen_banks
.iter()
.filter(|b| b.slot() < tower.root())
.count();
let last_voted_slot = tower.last_voted_slot();
let mut heaviest_bank_on_same_fork = None;
let mut heaviest_same_fork_weight = 0;
let stats: Vec<&ForkStats> = frozen_banks
.iter()
.map(|bank| {
// Only time progress map should be missing a bank slot
// is if this node was the leader for this slot as those banks
// are not replayed in replay_active_banks()
let stats = progress
.get_fork_stats(bank.slot())
.expect("All frozen banks must exist in the Progress map");
if let Some(last_voted_slot) = last_voted_slot {
if ancestors
.get(&bank.slot())
.expect("Entry in frozen banks must exist in ancestors")
.contains(&last_voted_slot)
{
// Descendant of last vote cannot be locked out
assert!(!stats.is_locked_out);
// ancestors(slot) should not contain the slot itself,
// so we should never get the same bank as the last vote
assert_ne!(bank.slot(), last_voted_slot);
// highest weight, lowest slot first. frozen_banks is sorted
// from least slot to greatest slot, so if two banks have
// the same fork weight, the lower slot will be picked
if stats.fork_weight > heaviest_same_fork_weight {
heaviest_bank_on_same_fork = Some(bank.clone());
heaviest_same_fork_weight = stats.fork_weight;
}
}
}
stats
})
.collect();
let num_not_recent = stats.iter().filter(|s| !s.is_recent).count();
let num_has_voted = stats.iter().filter(|s| s.has_voted).count();
let num_empty = stats.iter().filter(|s| s.is_empty).count();
let num_threshold_failure = stats.iter().filter(|s| !s.vote_threshold).count();
let num_votable_threshold_failure = stats
.iter()
.filter(|s| s.is_recent && !s.has_voted && !s.vote_threshold)
.count();
let mut candidates: Vec<_> = frozen_banks.iter().zip(stats.iter()).collect();
//highest weight, lowest slot first
candidates.sort_by_key(|b| (b.1.fork_weight, 0i64 - b.0.slot() as i64));
let rv = candidates
.last()
.expect("frozen banks was nonempty so candidates must also be nonempty");
let ms = timing::duration_as_ms(&tower_start.elapsed());
let weights: Vec<(u128, u64, u64)> = candidates
.iter()
.map(|x| (x.1.weight, x.0.slot(), x.1.block_height))
.collect();
debug!(
"@{:?} tower duration: {:?} len: {}/{} weights: {:?}",
timing::timestamp(),
ms,
candidates.len(),
stats.iter().filter(|s| !s.has_voted).count(),
weights,
);
datapoint_debug!(
"replay_stage-select_forks",
("frozen_banks", num_frozen_banks as i64, i64),
("not_recent", num_not_recent as i64, i64),
("has_voted", num_has_voted as i64, i64),
("old_banks", num_old_banks as i64, i64),
("empty_banks", num_empty as i64, i64),
("threshold_failure", num_threshold_failure as i64, i64),
(
"votable_threshold_failure",
num_votable_threshold_failure as i64,
i64
),
("tower_duration", ms as i64, i64),
);
(rv.0.clone(), heaviest_bank_on_same_fork)
}
fn mark_fork_invalid_candidate(&mut self, _invalid_slot: Slot) {}
fn mark_fork_valid_candidate(&mut self, _valid_slots: &[Slot]) {}
}

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@ use std::{
sync::{Arc, RwLock},
thread::{self, Builder, JoinHandle},
};
use tokio::runtime::Runtime;
use tokio::runtime;
// Delay uploading the largest confirmed root for this many slots. This is done in an attempt to
// ensure that the `CacheBlockTimeService` has had enough time to add the block time for the root
@@ -21,7 +21,7 @@ pub struct BigTableUploadService {
impl BigTableUploadService {
pub fn new(
runtime: Arc<Runtime>,
runtime_handle: runtime::Handle,
bigtable_ledger_storage: solana_storage_bigtable::LedgerStorage,
blockstore: Arc<Blockstore>,
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
@@ -32,7 +32,7 @@ impl BigTableUploadService {
.name("bigtable-upload".to_string())
.spawn(move || {
Self::run(
runtime,
runtime_handle,
bigtable_ledger_storage,
blockstore,
block_commitment_cache,
@@ -45,7 +45,7 @@ impl BigTableUploadService {
}
fn run(
runtime: Arc<Runtime>,
runtime: runtime::Handle,
bigtable_ledger_storage: solana_storage_bigtable::LedgerStorage,
blockstore: Arc<Blockstore>,
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
@@ -74,7 +74,6 @@ impl BigTableUploadService {
start_slot,
Some(end_slot),
true,
false,
exit.clone(),
));

View File

@@ -373,7 +373,7 @@ pub fn get_broadcast_peers(
/// # Remarks
pub fn broadcast_shreds(
s: &UdpSocket,
shreds: &[Shred],
shreds: &Arc<Vec<Shred>>,
peers_and_stakes: &[(u64, usize)],
peers: &[ContactInfo],
last_datapoint_submit: &Arc<AtomicU64>,
@@ -402,7 +402,7 @@ pub fn broadcast_shreds(
match send_mmsg(s, &packets[sent..]) {
Ok(n) => sent += n,
Err(e) => {
return Err(Error::Io(e));
return Err(Error::IO(e));
}
}
}
@@ -472,14 +472,12 @@ pub mod test {
) {
let num_entries = max_ticks_per_n_shreds(num, None);
let (data_shreds, _) = make_slot_entries(slot, 0, num_entries);
let keypair = Keypair::new();
let coding_shreds = Shredder::data_shreds_to_coding_shreds(
&keypair,
&data_shreds[0..],
RECOMMENDED_FEC_RATE,
&mut ProcessShredsStats::default(),
)
.unwrap();
let keypair = Arc::new(Keypair::new());
let shredder = Shredder::new(slot, 0, RECOMMENDED_FEC_RATE, keypair, 0, 0)
.expect("Expected to create a new shredder");
let coding_shreds = shredder
.data_shreds_to_coding_shreds(&data_shreds[0..], &mut ProcessShredsStats::default());
(
data_shreds.clone(),
coding_shreds.clone(),
@@ -669,6 +667,8 @@ pub mod test {
}
}
sleep(Duration::from_millis(2000));
trace!(
"[broadcast_ledger] max_tick_height: {}, start_tick_height: {}, ticks_per_slot: {}",
max_tick_height,
@@ -676,17 +676,10 @@ pub mod test {
ticks_per_slot,
);
let mut entries = vec![];
for _ in 0..10 {
entries = broadcast_service
.blockstore
.get_slot_entries(slot, 0)
.expect("Expect entries to be present");
if entries.len() >= max_tick_height as usize {
break;
}
sleep(Duration::from_millis(1000));
}
let blockstore = broadcast_service.blockstore;
let entries = blockstore
.get_slot_entries(slot, 0)
.expect("Expect entries to be present");
assert_eq!(entries.len(), max_tick_height as usize);
drop(entry_sender);

View File

@@ -1,6 +1,6 @@
use crate::poh_recorder::WorkingBankEntry;
use crate::result::Result;
use solana_ledger::{entry::Entry, shred::Shred};
use solana_ledger::entry::Entry;
use solana_runtime::bank::Bank;
use solana_sdk::clock::Slot;
use std::{
@@ -16,15 +16,11 @@ pub(super) struct ReceiveResults {
pub last_tick_height: u64,
}
#[derive(Clone)]
#[derive(Copy, Clone)]
pub struct UnfinishedSlotInfo {
pub next_shred_index: u32,
pub slot: Slot,
pub parent: Slot,
// Data shreds buffered to make a batch of size
// MAX_DATA_SHREDS_PER_FEC_BLOCK.
pub(crate) data_shreds_buffer: Vec<Shred>,
pub(crate) fec_set_offset: u32, // See Shredder::fec_set_index.
}
/// This parameter tunes how many entries are received in one iteration of recv loop

View File

@@ -7,13 +7,12 @@ use super::{
use crate::broadcast_stage::broadcast_utils::UnfinishedSlotInfo;
use solana_ledger::{
entry::Entry,
shred::{
ProcessShredsStats, Shred, Shredder, MAX_DATA_SHREDS_PER_FEC_BLOCK, RECOMMENDED_FEC_RATE,
SHRED_TICK_REFERENCE_MASK,
},
shred::{ProcessShredsStats, Shred, Shredder, RECOMMENDED_FEC_RATE, SHRED_TICK_REFERENCE_MASK},
};
use solana_sdk::{pubkey::Pubkey, signature::Keypair, timing::duration_as_us};
use std::{collections::HashMap, ops::Deref, sync::RwLock, time::Duration};
use std::collections::HashMap;
use std::sync::RwLock;
use std::time::Duration;
#[derive(Clone)]
pub struct StandardBroadcastRun {
@@ -41,114 +40,94 @@ impl StandardBroadcastRun {
pub(super) fn new(keypair: Arc<Keypair>, shred_version: u16) -> Self {
Self {
process_shreds_stats: ProcessShredsStats::default(),
transmit_shreds_stats: Arc::default(),
insert_shreds_stats: Arc::default(),
transmit_shreds_stats: Arc::new(Mutex::new(SlotBroadcastStats::default())),
insert_shreds_stats: Arc::new(Mutex::new(SlotBroadcastStats::default())),
unfinished_slot: None,
current_slot_and_parent: None,
slot_broadcast_start: None,
keypair,
shred_version,
last_datapoint_submit: Arc::default(),
last_datapoint_submit: Arc::new(AtomicU64::new(0)),
num_batches: 0,
broadcast_peer_cache: Arc::default(),
last_peer_update: Arc::default(),
broadcast_peer_cache: Arc::new(RwLock::new(BroadcastPeerCache::default())),
last_peer_update: Arc::new(AtomicU64::new(0)),
}
}
// If the current slot has changed, generates an empty shred indicating
// last shred in the previous slot, along with coding shreds for the data
// shreds buffered.
fn finish_prev_slot(
&mut self,
max_ticks_in_slot: u8,
stats: &mut ProcessShredsStats,
) -> Vec<Shred> {
let (current_slot, _) = self.current_slot_and_parent.unwrap();
match self.unfinished_slot {
None => Vec::default(),
Some(ref state) if state.slot == current_slot => Vec::default(),
Some(ref mut state) => {
let parent_offset = state.slot - state.parent;
let reference_tick = max_ticks_in_slot & SHRED_TICK_REFERENCE_MASK;
let fec_set_index =
Shredder::fec_set_index(state.next_shred_index, state.fec_set_offset);
let mut shred = Shred::new_from_data(
state.slot,
state.next_shred_index,
parent_offset as u16,
None, // data
true, // is_last_in_fec_set
true, // is_last_in_slot
reference_tick,
self.shred_version,
fec_set_index.unwrap(),
);
Shredder::sign_shred(self.keypair.deref(), &mut shred);
state.data_shreds_buffer.push(shred.clone());
let mut shreds = make_coding_shreds(
self.keypair.deref(),
&mut self.unfinished_slot,
true, // is_last_in_slot
stats,
);
shreds.insert(0, shred);
self.report_and_reset_stats();
self.unfinished_slot = None;
shreds
}
}
}
fn check_for_interrupted_slot(&mut self, max_ticks_in_slot: u8) -> Option<Shred> {
let (slot, _) = self.current_slot_and_parent.unwrap();
let mut last_unfinished_slot_shred = self
.unfinished_slot
.map(|last_unfinished_slot| {
if last_unfinished_slot.slot != slot {
self.report_and_reset_stats();
Some(Shred::new_from_data(
last_unfinished_slot.slot,
last_unfinished_slot.next_shred_index,
(last_unfinished_slot.slot - last_unfinished_slot.parent) as u16,
None,
true,
true,
max_ticks_in_slot & SHRED_TICK_REFERENCE_MASK,
self.shred_version,
last_unfinished_slot.next_shred_index,
))
} else {
None
}
})
.unwrap_or(None);
// This shred should only be Some if the previous slot was interrupted
if let Some(ref mut shred) = last_unfinished_slot_shred {
Shredder::sign_shred(&self.keypair, shred);
self.unfinished_slot = None;
}
last_unfinished_slot_shred
}
fn init_shredder(&self, blockstore: &Blockstore, reference_tick: u8) -> (Shredder, u32) {
let (slot, parent_slot) = self.current_slot_and_parent.unwrap();
let next_shred_index = self
.unfinished_slot
.map(|s| s.next_shred_index)
.unwrap_or_else(|| {
blockstore
.meta(slot)
.expect("Database error")
.map(|meta| meta.consumed)
.unwrap_or(0) as u32
});
(
Shredder::new(
slot,
parent_slot,
RECOMMENDED_FEC_RATE,
self.keypair.clone(),
reference_tick,
self.shred_version,
)
.expect("Expected to create a new shredder"),
next_shred_index,
)
}
fn entries_to_data_shreds(
&mut self,
shredder: &Shredder,
next_shred_index: u32,
entries: &[Entry],
blockstore: &Blockstore,
reference_tick: u8,
is_slot_end: bool,
process_stats: &mut ProcessShredsStats,
) -> Vec<Shred> {
let (slot, parent_slot) = self.current_slot_and_parent.unwrap();
let (next_shred_index, fec_set_offset) = match &self.unfinished_slot {
Some(state) => (state.next_shred_index, state.fec_set_offset),
None => match blockstore.meta(slot).unwrap() {
Some(slot_meta) => {
let shreds_consumed = slot_meta.consumed as u32;
(shreds_consumed, shreds_consumed)
}
None => (0, 0),
},
};
let (data_shreds, next_shred_index) = Shredder::new(
slot,
parent_slot,
RECOMMENDED_FEC_RATE,
self.keypair.clone(),
reference_tick,
self.shred_version,
)
.unwrap()
.entries_to_data_shreds(
entries,
is_slot_end,
next_shred_index,
fec_set_offset,
process_stats,
);
let mut data_shreds_buffer = match &mut self.unfinished_slot {
Some(state) => {
assert_eq!(state.slot, slot);
std::mem::take(&mut state.data_shreds_buffer)
}
None => Vec::default(),
};
data_shreds_buffer.extend(data_shreds.clone());
let (data_shreds, new_next_shred_index) =
shredder.entries_to_data_shreds(entries, is_slot_end, next_shred_index, process_stats);
self.unfinished_slot = Some(UnfinishedSlotInfo {
next_shred_index,
slot,
parent: parent_slot,
data_shreds_buffer,
fec_set_offset,
next_shred_index: new_next_shred_index,
slot: shredder.slot,
parent: shredder.parent_slot,
});
data_shreds
}
@@ -205,16 +184,19 @@ impl StandardBroadcastRun {
let mut to_shreds_time = Measure::start("broadcast_to_shreds");
// 1) Check if slot was interrupted
let prev_slot_shreds =
self.finish_prev_slot(bank.ticks_per_slot() as u8, &mut process_stats);
let last_unfinished_slot_shred =
self.check_for_interrupted_slot(bank.ticks_per_slot() as u8);
// 2) Convert entries to shreds and coding shreds
let is_last_in_slot = last_tick_height == bank.max_tick_height();
let reference_tick = bank.tick_height() % bank.ticks_per_slot();
let data_shreds = self.entries_to_data_shreds(
&receive_results.entries,
let (shredder, next_shred_index) = self.init_shredder(
blockstore,
reference_tick as u8,
(bank.tick_height() % bank.ticks_per_slot()) as u8,
);
let is_last_in_slot = last_tick_height == bank.max_tick_height();
let data_shreds = self.entries_to_data_shreds(
&shredder,
next_shred_index,
&receive_results.entries,
is_last_in_slot,
&mut process_stats,
);
@@ -226,25 +208,27 @@ impl StandardBroadcastRun {
.insert_shreds(first, None, true)
.expect("Failed to insert shreds in blockstore");
}
let last_data_shred = data_shreds.len();
to_shreds_time.stop();
let mut get_leader_schedule_time = Measure::start("broadcast_get_leader_schedule");
let bank_epoch = bank.get_leader_schedule_epoch(bank.slot());
let stakes = bank.epoch_staked_nodes(bank_epoch).map(Arc::new);
let stakes = bank.epoch_staked_nodes(bank_epoch);
let stakes = stakes.map(Arc::new);
// Broadcast the last shred of the interrupted slot if necessary
if !prev_slot_shreds.is_empty() {
if let Some(last_shred) = last_unfinished_slot_shred {
let batch_info = Some(BroadcastShredBatchInfo {
slot: prev_slot_shreds[0].slot(),
slot: last_shred.slot(),
num_expected_batches: Some(old_num_batches + 1),
slot_start_ts: old_broadcast_start.expect(
"Old broadcast start time for previous slot must exist if the previous slot
was interrupted",
),
});
let shreds = Arc::new(prev_slot_shreds);
socket_sender.send(((stakes.clone(), shreds.clone()), batch_info.clone()))?;
blockstore_sender.send((shreds, batch_info))?;
let last_shred = Arc::new(vec![last_shred]);
socket_sender.send(((stakes.clone(), last_shred.clone()), batch_info.clone()))?;
blockstore_sender.send((last_shred, batch_info))?;
}
// Increment by two batches, one for the data batch, one for the coding batch.
@@ -271,15 +255,11 @@ impl StandardBroadcastRun {
// Send data shreds
let data_shreds = Arc::new(data_shreds);
socket_sender.send(((stakes.clone(), data_shreds.clone()), batch_info.clone()))?;
blockstore_sender.send((data_shreds, batch_info.clone()))?;
blockstore_sender.send((data_shreds.clone(), batch_info.clone()))?;
// Create and send coding shreds
let coding_shreds = make_coding_shreds(
self.keypair.deref(),
&mut self.unfinished_slot,
is_last_in_slot,
&mut process_stats,
);
let coding_shreds = shredder
.data_shreds_to_coding_shreds(&data_shreds[0..last_data_shred], &mut process_stats);
let coding_shreds = Arc::new(coding_shreds);
socket_sender.send(((stakes, coding_shreds.clone()), batch_info.clone()))?;
blockstore_sender.send((coding_shreds, batch_info))?;
@@ -398,15 +378,15 @@ impl StandardBroadcastRun {
fn report_and_reset_stats(&mut self) {
let stats = &self.process_shreds_stats;
let unfinished_slot = self.unfinished_slot.as_ref().unwrap();
assert!(self.unfinished_slot.is_some());
datapoint_info!(
"broadcast-process-shreds-stats",
("slot", unfinished_slot.slot as i64, i64),
("slot", self.unfinished_slot.unwrap().slot as i64, i64),
("shredding_time", stats.shredding_elapsed, i64),
("receive_time", stats.receive_elapsed, i64),
(
"num_data_shreds",
unfinished_slot.next_shred_index as i64,
i64::from(self.unfinished_slot.unwrap().next_shred_index),
i64
),
(
@@ -429,33 +409,6 @@ impl StandardBroadcastRun {
}
}
// Consumes data_shreds_buffer returning corresponding coding shreds.
fn make_coding_shreds(
keypair: &Keypair,
unfinished_slot: &mut Option<UnfinishedSlotInfo>,
is_slot_end: bool,
stats: &mut ProcessShredsStats,
) -> Vec<Shred> {
let data_shreds = match unfinished_slot {
None => Vec::default(),
Some(unfinished_slot) => {
let size = unfinished_slot.data_shreds_buffer.len();
// Consume a multiple of 32, unless this is the slot end.
let offset = if is_slot_end {
0
} else {
size % MAX_DATA_SHREDS_PER_FEC_BLOCK as usize
};
unfinished_slot
.data_shreds_buffer
.drain(0..size - offset)
.collect()
}
};
Shredder::data_shreds_to_coding_shreds(keypair, &data_shreds, RECOMMENDED_FEC_RATE, stats)
.unwrap()
}
impl BroadcastRun for StandardBroadcastRun {
fn run(
&mut self,
@@ -465,8 +418,6 @@ impl BroadcastRun for StandardBroadcastRun {
blockstore_sender: &Sender<(Arc<Vec<Shred>>, Option<BroadcastShredBatchInfo>)>,
) -> Result<()> {
let receive_results = broadcast_utils::recv_slot_entries(receiver)?;
// TODO: Confirm that last chunk of coding shreds
// will not be lost or delayed for too long.
self.process_receive_results(
blockstore,
socket_sender,
@@ -557,8 +508,6 @@ mod test {
next_shred_index,
slot,
parent,
data_shreds_buffer: Vec::default(),
fec_set_offset: next_shred_index,
});
run.slot_broadcast_start = Some(Instant::now());
@@ -566,9 +515,8 @@ mod test {
run.current_slot_and_parent = Some((4, 2));
// Slot 2 interrupted slot 1
let shreds = run.finish_prev_slot(0, &mut ProcessShredsStats::default());
let shred = shreds
.get(0)
let shred = run
.check_for_interrupted_slot(0)
.expect("Expected a shred that signals an interrupt");
// Validate the shred
@@ -694,50 +642,6 @@ mod test {
);
}
#[test]
fn test_buffer_data_shreds() {
let num_shreds_per_slot = 2;
let (blockstore, genesis_config, _cluster_info, bank, leader_keypair, _socket) =
setup(num_shreds_per_slot);
let (bsend, brecv) = channel();
let (ssend, _srecv) = channel();
let mut last_tick_height = 0;
let mut standard_broadcast_run = StandardBroadcastRun::new(leader_keypair, 0);
let mut process_ticks = |num_ticks| {
let ticks = create_ticks(num_ticks, 0, genesis_config.hash());
last_tick_height += (ticks.len() - 1) as u64;
let receive_results = ReceiveResults {
entries: ticks,
time_elapsed: Duration::new(1, 0),
bank: bank.clone(),
last_tick_height,
};
standard_broadcast_run
.process_receive_results(&blockstore, &ssend, &bsend, receive_results)
.unwrap();
};
for i in 0..3 {
process_ticks((i + 1) * 100);
}
let mut shreds = Vec::<Shred>::new();
while let Ok((recv_shreds, _)) = brecv.recv_timeout(Duration::from_secs(1)) {
shreds.extend(recv_shreds.deref().clone());
}
assert!(shreds.len() < 32, "shreds.len(): {}", shreds.len());
assert!(shreds.iter().all(|shred| shred.is_data()));
process_ticks(75);
while let Ok((recv_shreds, _)) = brecv.recv_timeout(Duration::from_secs(1)) {
shreds.extend(recv_shreds.deref().clone());
}
assert!(shreds.len() > 64, "shreds.len(): {}", shreds.len());
let num_coding_shreds = shreds.iter().filter(|shred| shred.is_code()).count();
assert_eq!(
num_coding_shreds, 32,
"num coding shreds: {}",
num_coding_shreds
);
}
#[test]
fn test_slot_finish() {
// Setup

View File

@@ -113,14 +113,7 @@ const GOSSIP_PING_CACHE_TTL: Duration = Duration::from_secs(640);
pub const DEFAULT_CONTACT_DEBUG_INTERVAL_MILLIS: u64 = 10_000;
pub const DEFAULT_CONTACT_SAVE_INTERVAL_MILLIS: u64 = 60_000;
/// Minimum serialized size of a Protocol::PullResponse packet.
const PULL_RESPONSE_MIN_SERIALIZED_SIZE: usize = 161;
// Limit number of unique pubkeys in the crds table.
pub(crate) const CRDS_UNIQUE_PUBKEY_CAPACITY: usize = 4096;
/// Minimum stake that a node should have so that its CRDS values are
/// propagated through gossip (few types are exempted).
const MIN_STAKE_FOR_GOSSIP: u64 = solana_sdk::native_token::LAMPORTS_PER_SOL;
/// Minimum number of staked nodes for enforcing stakes in gossip.
const MIN_NUM_STAKED_NODES: usize = 500;
const PULL_RESPONSE_MIN_SERIALIZED_SIZE: usize = 167;
#[derive(Debug, PartialEq, Eq)]
pub enum ClusterInfoError {
@@ -252,6 +245,7 @@ struct GossipStats {
get_accounts_hash: Counter,
all_tvu_peers: Counter,
tvu_peers: Counter,
retransmit_peers: Counter,
repair_peers: Counter,
new_push_requests: Counter,
new_push_requests2: Counter,
@@ -263,17 +257,6 @@ struct GossipStats {
handle_batch_pull_requests_time: Counter,
handle_batch_pull_responses_time: Counter,
handle_batch_push_messages_time: Counter,
packets_received_count: Counter,
packets_received_prune_messages_count: Counter,
packets_received_pull_requests_count: Counter,
packets_received_pull_responses_count: Counter,
packets_received_push_messages_count: Counter,
packets_received_verified_count: Counter,
packets_sent_gossip_requests_count: Counter,
packets_sent_prune_messages_count: Counter,
packets_sent_pull_requests_count: Counter,
packets_sent_pull_responses_count: Counter,
packets_sent_push_messages_count: Counter,
process_gossip_packets_time: Counter,
process_pull_response: Counter,
process_pull_response_count: Counter,
@@ -291,10 +274,6 @@ struct GossipStats {
prune_message_len: Counter,
pull_request_ping_pong_check_failed_count: Counter,
purge: Counter,
require_stake_for_gossip_unknown_feature_set: Counter,
require_stake_for_gossip_unknown_stakes: Counter,
trim_crds_table_failed: Counter,
trim_crds_table_purged_values_count: Counter,
epoch_slots_lookup: Counter,
new_pull_requests: Counter,
new_pull_requests_count: Counter,
@@ -334,7 +313,7 @@ impl Default for ClusterInfo {
}
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, AbiExample)]
#[derive(Debug, Default, Deserialize, Serialize, AbiExample)]
pub struct PruneData {
/// Pubkey of the node that sent this prune data
pub pubkey: Pubkey,
@@ -426,7 +405,7 @@ pub fn make_accounts_hashes_message(
type Ping = ping_pong::Ping<[u8; GOSSIP_PING_TOKEN_SIZE]>;
// TODO These messages should go through the gpu pipeline for spam filtering
#[frozen_abi(digest = "CH5BWuhAyvUiUQYgu2Lcwu7eoiW6bQitvtLS1yFsdmrE")]
#[frozen_abi(digest = "DdTxrwwnbe571Di4rLtrAQorFDE58vYnmzzbaeQ7sQMC")]
#[derive(Serialize, Deserialize, Debug, AbiEnumVisitor, AbiExample)]
#[allow(clippy::large_enum_variant)]
enum Protocol {
@@ -434,8 +413,6 @@ enum Protocol {
PullRequest(CrdsFilter, CrdsValue),
PullResponse(Pubkey, Vec<CrdsValue>),
PushMessage(Pubkey, Vec<CrdsValue>),
// TODO: Remove the redundant outer pubkey here,
// and use the inner PruneData.pubkey instead.
PruneMessage(Pubkey, PruneData),
PingMessage(Ping),
PongMessage(Pong),
@@ -519,13 +496,7 @@ impl Sanitize for Protocol {
}
Protocol::PullResponse(_, val) => val.sanitize(),
Protocol::PushMessage(_, val) => val.sanitize(),
Protocol::PruneMessage(from, val) => {
if *from != val.pubkey {
Err(SanitizeError::InvalidValue)
} else {
val.sanitize()
}
}
Protocol::PruneMessage(_, val) => val.sanitize(),
Protocol::PingMessage(ping) => ping.sanitize(),
Protocol::PongMessage(pong) => pong.sanitize(),
}
@@ -543,33 +514,6 @@ struct ResponseScore {
score: u64, // Relative score of the response
}
// Retains only CRDS values associated with nodes with enough stake.
// (some crds types are exempted)
fn retain_staked(values: &mut Vec<CrdsValue>, stakes: &HashMap<Pubkey, u64>) {
values.retain(|value| {
match value.data {
CrdsData::ContactInfo(_) => true,
// May Impact new validators starting up without any stake yet.
CrdsData::Vote(_, _) => true,
// Unstaked nodes can still help repair.
CrdsData::EpochSlots(_, _) => true,
// Unstaked nodes can still serve snapshots.
CrdsData::SnapshotHashes(_) => true,
// Otherwise unstaked voting nodes will show up with no version in
// the various dashboards.
CrdsData::Version(_) => true,
CrdsData::LowestSlot(_, _)
| CrdsData::AccountsHashes(_)
| CrdsData::LegacyVersion(_)
| CrdsData::NodeInstance(_)
| CrdsData::DuplicateShred(_, _) => {
let stake = stakes.get(&value.pubkey()).copied();
stake.unwrap_or_default() >= MIN_STAKE_FOR_GOSSIP
}
}
})
}
impl ClusterInfo {
/// Without a valid keypair gossip will not function. Only useful for tests.
pub fn new_with_invalid_keypair(contact_info: ContactInfo) -> Self {
@@ -640,6 +584,16 @@ impl ClusterInfo {
self.contact_debug_interval = new;
}
pub fn update_contact_info<F>(&self, modify: F)
where
F: FnOnce(&mut ContactInfo),
{
let my_id = self.id();
modify(&mut self.my_contact_info.write().unwrap());
assert_eq!(self.my_contact_info.read().unwrap().id, my_id);
self.insert_self()
}
fn push_self(
&self,
stakes: &HashMap<Pubkey, u64>,
@@ -1269,30 +1223,23 @@ impl ClusterInfo {
.map(|x| map(x.value.lowest_slot().unwrap(), x.insert_timestamp))
}
pub fn get_epoch_slots_since(
&self,
timestamp: u64,
) -> (
Vec<EpochSlots>,
Option<u64>, // Most recent insert timestmap.
) {
let mut max_ts = 0;
pub fn get_epoch_slots_since(&self, since: Option<u64>) -> (Vec<EpochSlots>, Option<u64>) {
let vals: Vec<_> = self
.gossip
.read()
.unwrap()
.crds
.get_epoch_slots_since(timestamp)
.map(|value| {
max_ts = std::cmp::max(max_ts, value.insert_timestamp);
match &value.value.data {
CrdsData::EpochSlots(_, slots) => slots.clone(),
_ => panic!("this should not happen!"),
}
.values()
.filter(|x| {
since
.map(|since| x.insert_timestamp > since)
.unwrap_or(true)
})
.filter_map(|x| Some((x.value.epoch_slots()?.clone(), x.insert_timestamp)))
.collect();
let max_ts = if vals.is_empty() { None } else { Some(max_ts) };
(vals, max_ts)
let max = vals.iter().map(|x| x.1).max().or(since);
let vec = vals.into_iter().map(|x| x.0).collect();
(vec, max)
}
pub fn get_node_version(&self, pubkey: &Pubkey) -> Option<solana_version::Version> {
@@ -1382,6 +1329,21 @@ impl ClusterInfo {
.collect()
}
/// all peers that have a valid tvu
pub fn retransmit_peers(&self) -> Vec<ContactInfo> {
self.time_gossip_read_lock("retransmit_peers", &self.stats.retransmit_peers)
.crds
.get_nodes_contact_info()
.filter(|x| {
x.id != self.id()
&& x.shred_version == self.my_shred_version()
&& ContactInfo::is_valid_address(&x.tvu)
&& ContactInfo::is_valid_address(&x.tvu_forwards)
})
.cloned()
.collect()
}
/// all tvu peers with valid gossip addrs that likely have the slot being requested
pub fn repair_peers(&self, slot: Slot) -> Vec<ContactInfo> {
let mut time = Measure::start("repair_peers");
@@ -1445,9 +1407,9 @@ impl ClusterInfo {
stakes_and_index: &[(u64, usize)],
seed: [u8; 32],
) -> Vec<(u64, usize)> {
let stake_weights: Vec<_> = stakes_and_index.iter().map(|(w, _)| *w).collect();
let stake_weights = stakes_and_index.iter().map(|(w, _)| *w).collect();
let shuffle = weighted_shuffle(&stake_weights, seed);
let shuffle = weighted_shuffle(stake_weights, seed);
shuffle.iter().map(|x| stakes_and_index[*x]).collect()
}
@@ -1457,7 +1419,7 @@ impl ClusterInfo {
&self,
stakes: Option<&HashMap<Pubkey, u64>>,
) -> (Vec<ContactInfo>, Vec<(u64, usize)>) {
let mut peers = self.tvu_peers();
let mut peers = self.retransmit_peers();
// insert "self" into this list for the layer and neighborhood computation
peers.push(self.my_contact_info());
let stakes_and_index = ClusterInfo::sorted_stakes_with_index(&peers, stakes);
@@ -1504,22 +1466,20 @@ impl ClusterInfo {
pub fn retransmit_to(
peers: &[&ContactInfo],
packet: &mut Packet,
slot_leader_pubkey: Option<Pubkey>,
s: &UdpSocket,
forwarded: bool,
) -> Result<()> {
trace!("retransmit orders {}", peers.len());
let dests: Vec<_> = if forwarded {
peers
.iter()
.map(|peer| &peer.tvu_forwards)
.filter(|addr| ContactInfo::is_valid_address(addr))
.collect()
} else {
peers.iter().map(|peer| &peer.tvu).collect()
};
let dests: Vec<_> = peers
.iter()
.filter(|v| v.id != slot_leader_pubkey.unwrap_or_default())
.map(|v| if forwarded { &v.tvu_forwards } else { &v.tvu })
.collect();
let mut sent = 0;
while sent < dests.len() {
match multicast(s, &packet.data[..packet.meta.size], &dests[sent..]) {
match multicast(s, &mut packet.data[..packet.meta.size], &dests[sent..]) {
Ok(n) => sent += n,
Err(e) => {
inc_new_counter_error!(
@@ -1528,7 +1488,7 @@ impl ClusterInfo {
1
);
error!("retransmit result {:?}", e);
return Err(Error::Io(e));
return Err(Error::IO(e));
}
}
}
@@ -1703,21 +1663,11 @@ impl ClusterInfo {
let mut gossip = self.gossip.write().unwrap();
gossip.process_push_messages(pending_push_messages);
}
fn new_push_requests(
&self,
stakes: &HashMap<Pubkey, u64>,
require_stake_for_gossip: bool,
) -> Vec<(SocketAddr, Protocol)> {
fn new_push_requests(&self) -> Vec<(SocketAddr, Protocol)> {
let self_id = self.id();
let mut push_messages = self
let (_, push_messages) = self
.time_gossip_write_lock("new_push_requests", &self.stats.new_push_requests)
.new_push_messages(self.drain_push_queue(), timestamp());
if require_stake_for_gossip {
push_messages.retain(|_, data| {
retain_staked(data, stakes);
!data.is_empty()
})
}
let push_messages: Vec<_> = {
let gossip =
self.time_gossip_read_lock("push_req_lookup", &self.stats.new_push_requests2);
@@ -1749,21 +1699,14 @@ impl ClusterInfo {
gossip_validators: Option<&HashSet<Pubkey>>,
stakes: &HashMap<Pubkey, u64>,
generate_pull_requests: bool,
require_stake_for_gossip: bool,
) -> Vec<(SocketAddr, Protocol)> {
self.trim_crds_table(CRDS_UNIQUE_PUBKEY_CAPACITY, &stakes);
let mut pulls: Vec<_> = if generate_pull_requests {
self.new_pull_requests(&thread_pool, gossip_validators, stakes)
} else {
vec![]
};
let mut pushes: Vec<_> = self.new_push_requests(stakes, require_stake_for_gossip);
self.stats
.packets_sent_pull_requests_count
.add_relaxed(pulls.len() as u64);
self.stats
.packets_sent_push_messages_count
.add_relaxed(pushes.len() as u64);
let mut pushes: Vec<_> = self.new_push_requests();
pulls.append(&mut pushes);
pulls
}
@@ -1777,20 +1720,15 @@ impl ClusterInfo {
stakes: &HashMap<Pubkey, u64>,
sender: &PacketSender,
generate_pull_requests: bool,
require_stake_for_gossip: bool,
) -> Result<()> {
let reqs = self.generate_new_gossip_requests(
thread_pool,
gossip_validators,
stakes,
&stakes,
generate_pull_requests,
require_stake_for_gossip,
);
if !reqs.is_empty() {
let packets = to_packets_with_destination(recycler.clone(), &reqs);
self.stats
.packets_sent_gossip_requests_count
.add_relaxed(packets.packets.len() as u64);
sender.send(packets)?;
}
Ok(())
@@ -1867,39 +1805,6 @@ impl ClusterInfo {
inc_new_counter_info!("cluster_info-purge-count", num_purged);
}
// Trims the CRDS table by dropping all values associated with the pubkeys
// with the lowest stake, so that the number of unique pubkeys are bounded.
fn trim_crds_table(&self, cap: usize, stakes: &HashMap<Pubkey, u64>) {
if !self.gossip.read().unwrap().crds.should_trim(cap) {
return;
}
let keep: Vec<_> = self
.entrypoints
.read()
.unwrap()
.iter()
.map(|k| k.id)
.chain(std::iter::once(self.id))
.collect();
let mut gossip = self.gossip.write().unwrap();
match gossip.crds.trim(cap, &keep, stakes) {
Err(err) => {
self.stats.trim_crds_table_failed.add_relaxed(1);
error!("crds table trim failed: {:?}", err);
}
Ok(purged_values) => {
self.stats
.trim_crds_table_purged_values_count
.add_relaxed(purged_values.len() as u64);
gossip.pull.purged_values.extend(
purged_values
.into_iter()
.map(|v| (v.value_hash, v.local_timestamp)),
);
}
}
}
/// randomly pick a node and ask them for updates asynchronously
pub fn gossip(
self: Arc<Self>,
@@ -1921,7 +1826,7 @@ impl ClusterInfo {
let mut last_contact_info_trace = timestamp();
let mut last_contact_info_save = timestamp();
let mut entrypoints_processed = false;
let recycler = PacketsRecycler::new_without_limit("gossip-recycler-shrink-stats");
let recycler = PacketsRecycler::default();
let crds_data = vec![
CrdsData::Version(Version::new(self.id())),
CrdsData::NodeInstance(self.instance.with_wallclock(timestamp())),
@@ -1953,18 +1858,13 @@ impl ClusterInfo {
last_contact_info_save = start;
}
let (stakes, feature_set) = match bank_forks {
let stakes: HashMap<_, _> = match bank_forks {
Some(ref bank_forks) => {
let root_bank = bank_forks.read().unwrap().root_bank();
(
root_bank.staked_nodes(),
Some(root_bank.feature_set.clone()),
)
bank_forks.read().unwrap().root_bank().staked_nodes()
}
None => (HashMap::new(), None),
None => HashMap::new(),
};
let require_stake_for_gossip =
self.require_stake_for_gossip(feature_set.as_deref(), &stakes);
let _ = self.run_gossip(
&thread_pool,
gossip_validators.as_ref(),
@@ -1972,7 +1872,6 @@ impl ClusterInfo {
&stakes,
&sender,
generate_pull_requests,
require_stake_for_gossip,
);
if exit.load(Ordering::Relaxed) {
return;
@@ -2053,7 +1952,6 @@ impl ClusterInfo {
stakes: &HashMap<Pubkey, u64>,
response_sender: &PacketSender,
feature_set: Option<&FeatureSet>,
require_stake_for_gossip: bool,
) {
let _st = ScopedTimer::from(&self.stats.handle_batch_pull_requests_time);
if requests.is_empty() {
@@ -2095,17 +1993,8 @@ impl ClusterInfo {
self.stats
.pull_requests_count
.add_relaxed(requests.len() as u64);
let response = self.handle_pull_requests(
recycler,
requests,
stakes,
feature_set,
require_stake_for_gossip,
);
let response = self.handle_pull_requests(recycler, requests, stakes, feature_set);
if !response.is_empty() {
self.stats
.packets_sent_pull_responses_count
.add_relaxed(response.packets.len() as u64);
let _ = response_sender.send(response);
}
}
@@ -2178,7 +2067,6 @@ impl ClusterInfo {
requests: Vec<PullData>,
stakes: &HashMap<Pubkey, u64>,
feature_set: Option<&FeatureSet>,
require_stake_for_gossip: bool,
) -> Packets {
let mut time = Measure::start("handle_pull_requests");
let callers = crds_value::filter_current(requests.iter().map(|r| &r.caller));
@@ -2186,7 +2074,7 @@ impl ClusterInfo {
.process_pull_requests(callers.cloned(), timestamp());
let output_size_limit =
self.update_data_budget(stakes.len()) / PULL_RESPONSE_MIN_SERIALIZED_SIZE;
let mut packets = Packets::new_with_recycler(recycler.clone(), 64).unwrap();
let mut packets = Packets::new_with_recycler(recycler.clone(), 64, "handle_pull_requests");
let (caller_and_filters, addrs): (Vec<_>, Vec<_>) = {
let mut rng = rand::thread_rng();
let check_pull_request =
@@ -2200,17 +2088,13 @@ impl ClusterInfo {
let now = timestamp();
let self_id = self.id();
let mut pull_responses = self
let pull_responses = self
.time_gossip_read_lock(
"generate_pull_responses",
&self.stats.generate_pull_responses,
)
.generate_pull_responses(&caller_and_filters, output_size_limit, now);
if require_stake_for_gossip {
for resp in &mut pull_responses {
retain_staked(resp, stakes);
}
}
let pull_responses: Vec<_> = pull_responses
.into_iter()
.zip(addrs.into_iter())
@@ -2475,7 +2359,8 @@ impl ClusterInfo {
if packets.is_empty() {
None
} else {
let packets = Packets::new_with_recycler_data(recycler, packets).unwrap();
let packets =
Packets::new_with_recycler_data(recycler, "handle_ping_messages", packets);
Some(packets)
}
}
@@ -2501,7 +2386,6 @@ impl ClusterInfo {
recycler: &PacketsRecycler,
stakes: &HashMap<Pubkey, u64>,
response_sender: &PacketSender,
require_stake_for_gossip: bool,
) {
let _st = ScopedTimer::from(&self.stats.handle_batch_push_messages_time);
if messages.is_empty() {
@@ -2607,11 +2491,10 @@ impl ClusterInfo {
return;
}
let mut packets = to_packets_with_destination(recycler.clone(), &prune_messages);
let num_prune_packets = packets.packets.len();
self.stats
.push_response_count
.add_relaxed(packets.packets.len() as u64);
let new_push_requests = self.new_push_requests(stakes, require_stake_for_gossip);
let new_push_requests = self.new_push_requests();
inc_new_counter_debug!("cluster_info-push_message-pushes", new_push_requests.len());
for (address, request) in new_push_requests {
if ContactInfo::is_valid_address(&address) {
@@ -2623,12 +2506,6 @@ impl ClusterInfo {
trace!("Dropping Gossip push response, as destination is unknown");
}
}
self.stats
.packets_sent_prune_messages_count
.add_relaxed(num_prune_packets as u64);
self.stats
.packets_sent_push_messages_count
.add_relaxed((packets.packets.len() - num_prune_packets) as u64);
let _ = response_sender.send(packets);
}
@@ -2654,33 +2531,6 @@ impl ClusterInfo {
}
}
fn require_stake_for_gossip(
&self,
feature_set: Option<&FeatureSet>,
stakes: &HashMap<Pubkey, u64>,
) -> bool {
match feature_set {
None => {
self.stats
.require_stake_for_gossip_unknown_feature_set
.add_relaxed(1);
false
}
Some(feature_set) => {
if !feature_set.is_active(&feature_set::require_stake_for_gossip::id()) {
false
} else if stakes.len() < MIN_NUM_STAKED_NODES {
self.stats
.require_stake_for_gossip_unknown_stakes
.add_relaxed(1);
false
} else {
true
}
}
}
}
fn process_packets(
&self,
packets: VecDeque<Packet>,
@@ -2693,9 +2543,6 @@ impl ClusterInfo {
should_check_duplicate_instance: bool,
) -> Result<()> {
let _st = ScopedTimer::from(&self.stats.process_gossip_packets_time);
self.stats
.packets_received_count
.add_relaxed(packets.len() as u64);
let packets: Vec<_> = thread_pool.install(|| {
packets
.into_par_iter()
@@ -2708,9 +2555,6 @@ impl ClusterInfo {
})
.collect()
});
self.stats
.packets_received_verified_count
.add_relaxed(packets.len() as u64);
// Check if there is a duplicate instance of
// this node with more recent timestamp.
let check_duplicate_instance = |values: &[CrdsValue]| {
@@ -2748,29 +2592,6 @@ impl ClusterInfo {
Protocol::PongMessage(pong) => pong_messages.push((from_addr, pong)),
}
}
self.stats
.packets_received_pull_requests_count
.add_relaxed(pull_requests.len() as u64);
self.stats
.packets_received_pull_responses_count
.add_relaxed(pull_responses.len() as u64);
self.stats
.packets_received_push_messages_count
.add_relaxed(push_messages.len() as u64);
self.stats
.packets_received_prune_messages_count
.add_relaxed(prune_messages.len() as u64);
let require_stake_for_gossip = self.require_stake_for_gossip(feature_set, &stakes);
if require_stake_for_gossip {
for (_, data) in &mut pull_responses {
retain_staked(data, &stakes);
}
for (_, data) in &mut push_messages {
retain_staked(data, &stakes);
}
pull_responses.retain(|(_, data)| !data.is_empty());
push_messages.retain(|(_, data)| !data.is_empty());
}
self.handle_batch_ping_messages(ping_messages, recycler, response_sender);
self.handle_batch_prune_messages(prune_messages);
self.handle_batch_push_messages(
@@ -2779,10 +2600,8 @@ impl ClusterInfo {
recycler,
&stakes,
response_sender,
require_stake_for_gossip,
);
self.handle_batch_pull_responses(pull_responses, thread_pool, &stakes, epoch_time_ms);
self.trim_crds_table(CRDS_UNIQUE_PUBKEY_CAPACITY, &stakes);
self.handle_batch_pong_messages(pong_messages, Instant::now());
self.handle_batch_pull_requests(
pull_requests,
@@ -2791,7 +2610,6 @@ impl ClusterInfo {
&stakes,
response_sender,
feature_set,
require_stake_for_gossip,
);
Ok(())
}
@@ -2888,6 +2706,7 @@ impl ClusterInfo {
self.stats.gossip_packets_dropped_count.clear(),
i64
),
("retransmit_peers", self.stats.retransmit_peers.clear(), i64),
("repair_peers", self.stats.repair_peers.clear(), i64),
(
"new_push_requests",
@@ -3075,83 +2894,6 @@ impl ClusterInfo {
self.stats.pull_requests_count.clear(),
i64
),
(
"packets_received_count",
self.stats.packets_received_count.clear(),
i64
),
(
"packets_received_prune_messages_count",
self.stats.packets_received_prune_messages_count.clear(),
i64
),
(
"packets_received_pull_requests_count",
self.stats.packets_received_pull_requests_count.clear(),
i64
),
(
"packets_received_pull_responses_count",
self.stats.packets_received_pull_responses_count.clear(),
i64
),
(
"packets_received_push_messages_count",
self.stats.packets_received_push_messages_count.clear(),
i64
),
(
"packets_received_verified_count",
self.stats.packets_received_verified_count.clear(),
i64
),
(
"packets_sent_gossip_requests_count",
self.stats.packets_sent_gossip_requests_count.clear(),
i64
),
(
"packets_sent_prune_messages_count",
self.stats.packets_sent_prune_messages_count.clear(),
i64
),
(
"packets_sent_pull_requests_count",
self.stats.packets_sent_pull_requests_count.clear(),
i64
),
(
"packets_sent_pull_responses_count",
self.stats.packets_sent_pull_responses_count.clear(),
i64
),
(
"packets_sent_push_messages_count",
self.stats.packets_sent_push_messages_count.clear(),
i64
),
(
"require_stake_for_gossip_unknown_feature_set",
self.stats
.require_stake_for_gossip_unknown_feature_set
.clear(),
i64
),
(
"require_stake_for_gossip_unknown_stakes",
self.stats.require_stake_for_gossip_unknown_stakes.clear(),
i64
),
(
"trim_crds_table_failed",
self.stats.trim_crds_table_failed.clear(),
i64
),
(
"trim_crds_table_purged_values_count",
self.stats.trim_crds_table_purged_values_count.clear(),
i64
),
);
*last_print = Instant::now();
@@ -3167,8 +2909,7 @@ impl ClusterInfo {
exit: &Arc<AtomicBool>,
) -> JoinHandle<()> {
let exit = exit.clone();
let recycler =
PacketsRecycler::new_without_limit("cluster-info-listen-recycler-shrink-stats");
let recycler = PacketsRecycler::default();
Builder::new()
.name("solana-listen".to_string())
.spawn(move || {
@@ -3466,7 +3207,6 @@ mod tests {
};
use itertools::izip;
use rand::seq::SliceRandom;
use serial_test::serial;
use solana_ledger::shred::Shredder;
use solana_sdk::signature::{Keypair, Signer};
use solana_vote_program::{vote_instruction, vote_state::Vote};
@@ -3614,7 +3354,7 @@ mod tests {
.iter()
.map(|ping| Pong::new(ping, &this_node).unwrap())
.collect();
let recycler = PacketsRecycler::new_without_limit("");
let recycler = PacketsRecycler::default();
let packets = cluster_info
.handle_ping_messages(
remote_nodes
@@ -3808,11 +3548,7 @@ mod tests {
let crds_values = vec![CrdsValue::new_rand(&mut rng, None)];
let pull_response = Protocol::PullResponse(Pubkey::new_unique(), crds_values);
let size = serialized_size(&pull_response).unwrap();
assert!(
PULL_RESPONSE_MIN_SERIALIZED_SIZE as u64 <= size,
"pull-response serialized size: {}",
size
);
assert!(PULL_RESPONSE_MIN_SERIALIZED_SIZE as u64 <= size);
}
}
@@ -3829,13 +3565,8 @@ mod tests {
.write()
.unwrap()
.refresh_push_active_set(&HashMap::new(), None);
let reqs = cluster_info.generate_new_gossip_requests(
&thread_pool,
None, // gossip_validators
&HashMap::new(),
true, // generate_pull_requests
false, // require_stake_for_gossip
);
let reqs =
cluster_info.generate_new_gossip_requests(&thread_pool, None, &HashMap::new(), true);
//assert none of the addrs are invalid.
reqs.iter().all(|(addr, _)| {
let res = ContactInfo::is_valid_address(addr);
@@ -3866,6 +3597,40 @@ mod tests {
.lookup(&label)
.is_some());
}
#[test]
#[should_panic]
fn test_update_contact_info() {
let d = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), timestamp());
let cluster_info = ClusterInfo::new_with_invalid_keypair(d);
let entry_label = CrdsValueLabel::ContactInfo(cluster_info.id());
assert!(cluster_info
.gossip
.read()
.unwrap()
.crds
.lookup(&entry_label)
.is_some());
let now = timestamp();
cluster_info.update_contact_info(|ci| ci.wallclock = now);
assert_eq!(
cluster_info
.gossip
.read()
.unwrap()
.crds
.lookup(&entry_label)
.unwrap()
.contact_info()
.unwrap()
.wallclock,
now
);
// Inserting Contactinfo with different pubkey should panic,
// and update should fail
cluster_info.update_contact_info(|ci| ci.id = solana_sdk::pubkey::new_rand())
}
fn assert_in_range(x: u16, range: (u16, u16)) {
assert!(x >= range.0);
@@ -3946,7 +3711,7 @@ mod tests {
.unwrap()
.refresh_push_active_set(&HashMap::new(), None);
//check that all types of gossip messages are signed correctly
let push_messages = cluster_info
let (_, push_messages) = cluster_info
.gossip
.write()
.unwrap()
@@ -4103,23 +3868,23 @@ mod tests {
let keys = Keypair::new();
let contact_info = ContactInfo::new_localhost(&keys.pubkey(), 0);
let cluster_info = ClusterInfo::new_with_invalid_keypair(contact_info);
let (slots, since) = cluster_info.get_epoch_slots_since(0);
let (slots, since) = cluster_info.get_epoch_slots_since(None);
assert!(slots.is_empty());
assert!(since.is_none());
cluster_info.push_epoch_slots(&[0]);
cluster_info.flush_push_queue();
let (slots, since) = cluster_info.get_epoch_slots_since(std::u64::MAX);
let (slots, since) = cluster_info.get_epoch_slots_since(Some(std::u64::MAX));
assert!(slots.is_empty());
assert_eq!(since, None);
assert_eq!(since, Some(std::u64::MAX));
let (slots, since) = cluster_info.get_epoch_slots_since(0);
let (slots, since) = cluster_info.get_epoch_slots_since(None);
assert_eq!(slots.len(), 1);
assert!(since.is_some());
let (slots, since2) = cluster_info.get_epoch_slots_since(since.unwrap() + 1);
let (slots, since2) = cluster_info.get_epoch_slots_since(since);
assert!(slots.is_empty());
assert_eq!(since2, None);
assert_eq!(since2, since);
}
#[test]
@@ -4404,23 +4169,6 @@ mod tests {
assert_eq!(msg.sanitize(), Err(SanitizeError::ValueOutOfBounds));
}
#[test]
fn test_protocol_prune_message_sanitize() {
let keypair = Keypair::new();
let mut prune_data = PruneData {
pubkey: keypair.pubkey(),
prunes: vec![],
signature: Signature::default(),
destination: Pubkey::new_unique(),
wallclock: timestamp(),
};
prune_data.sign(&keypair);
let prune_message = Protocol::PruneMessage(keypair.pubkey(), prune_data.clone());
assert_eq!(prune_message.sanitize(), Ok(()));
let prune_message = Protocol::PruneMessage(Pubkey::new_unique(), prune_data);
assert_eq!(prune_message.sanitize(), Err(SanitizeError::InvalidValue));
}
// computes the maximum size for pull request blooms
fn max_bloom_size() -> usize {
let filter_size = serialized_size(&CrdsFilter::default())
@@ -4452,7 +4200,7 @@ mod tests {
cluster_info.flush_push_queue();
cluster_info.push_epoch_slots(&range[16000..]);
cluster_info.flush_push_queue();
let (slots, since) = cluster_info.get_epoch_slots_since(0);
let (slots, since) = cluster_info.get_epoch_slots_since(None);
let slots: Vec<_> = slots.iter().flat_map(|x| x.to_slots(0)).collect();
assert_eq!(slots, range);
assert!(since.is_some());
@@ -4743,54 +4491,4 @@ mod tests {
}
}
}
#[test]
#[serial]
fn test_pull_request_time_pruning() {
let node = Node::new_localhost();
let cluster_info = Arc::new(ClusterInfo::new_with_invalid_keypair(node.info));
let entrypoint_pubkey = solana_sdk::pubkey::new_rand();
let entrypoint = ContactInfo::new_localhost(&entrypoint_pubkey, timestamp());
cluster_info.set_entrypoint(entrypoint);
let mut rng = rand::thread_rng();
let shred_version = cluster_info.my_shred_version();
let mut peers: Vec<Pubkey> = vec![];
const NO_ENTRIES: usize = CRDS_UNIQUE_PUBKEY_CAPACITY + 128;
let data: Vec<_> = repeat_with(|| {
let keypair = Keypair::new();
peers.push(keypair.pubkey());
let mut rand_ci = ContactInfo::new_rand(&mut rng, Some(keypair.pubkey()));
rand_ci.shred_version = shred_version;
rand_ci.wallclock = timestamp();
CrdsValue::new_signed(CrdsData::ContactInfo(rand_ci), &keypair)
})
.take(NO_ENTRIES)
.collect();
let timeouts = cluster_info.gossip.read().unwrap().make_timeouts_test();
assert_eq!(
(0, 0, NO_ENTRIES),
cluster_info.handle_pull_response(&entrypoint_pubkey, data, &timeouts)
);
let now = timestamp();
for peer in peers {
cluster_info
.gossip
.write()
.unwrap()
.mark_pull_request_creation_time(&peer, now);
}
assert_eq!(
cluster_info
.gossip
.read()
.unwrap()
.pull
.pull_request_time
.len(),
CRDS_UNIQUE_PUBKEY_CAPACITY
);
}
}

View File

@@ -4,7 +4,6 @@ use crate::{
optimistic_confirmation_verifier::OptimisticConfirmationVerifier,
optimistically_confirmed_bank_tracker::{BankNotification, BankNotificationSender},
poh_recorder::PohRecorder,
replay_stage::DUPLICATE_THRESHOLD,
result::{Error, Result},
rpc_subscriptions::RpcSubscriptions,
sigverify,
@@ -22,7 +21,6 @@ use solana_perf::packet::{self, Packets};
use solana_runtime::{
bank::Bank,
bank_forks::BankForks,
commitment::VOTE_THRESHOLD_SIZE,
epoch_stakes::{EpochAuthorizedVoters, EpochStakes},
stakes::Stakes,
vote_sender_types::{ReplayVoteReceiver, ReplayedVote},
@@ -46,17 +44,12 @@ use std::{
};
// Map from a vote account to the authorized voter for an epoch
pub type ThresholdConfirmedSlots = Vec<(Slot, Hash)>;
pub type VerifiedLabelVotePacketsSender = CrossbeamSender<Vec<(CrdsValueLabel, Slot, Packets)>>;
pub type VerifiedLabelVotePacketsReceiver = CrossbeamReceiver<Vec<(CrdsValueLabel, Slot, Packets)>>;
pub type VerifiedLabelVotePacketsSender = CrossbeamSender<Vec<(CrdsValueLabel, Packets)>>;
pub type VerifiedLabelVotePacketsReceiver = CrossbeamReceiver<Vec<(CrdsValueLabel, Packets)>>;
pub type VerifiedVoteTransactionsSender = CrossbeamSender<Vec<Transaction>>;
pub type VerifiedVoteTransactionsReceiver = CrossbeamReceiver<Vec<Transaction>>;
pub type VerifiedVoteSender = CrossbeamSender<(Pubkey, Vec<Slot>)>;
pub type VerifiedVoteReceiver = CrossbeamReceiver<(Pubkey, Vec<Slot>)>;
pub type GossipDuplicateConfirmedSlotsSender = CrossbeamSender<ThresholdConfirmedSlots>;
pub type GossipDuplicateConfirmedSlotsReceiver = CrossbeamReceiver<ThresholdConfirmedSlots>;
const THRESHOLDS_TO_CHECK: [f64; 2] = [DUPLICATE_THRESHOLD, VOTE_THRESHOLD_SIZE];
#[derive(Default)]
pub struct SlotVoteTracker {
@@ -252,7 +245,6 @@ impl ClusterInfoVoteListener {
replay_votes_receiver: ReplayVoteReceiver,
blockstore: Arc<Blockstore>,
bank_notification_sender: Option<BankNotificationSender>,
cluster_confirmed_slot_sender: GossipDuplicateConfirmedSlotsSender,
) -> Self {
let exit_ = exit.clone();
@@ -299,7 +291,6 @@ impl ClusterInfoVoteListener {
replay_votes_receiver,
blockstore,
bank_notification_sender,
cluster_confirmed_slot_sender,
);
})
.unwrap();
@@ -341,28 +332,34 @@ impl ClusterInfoVoteListener {
}
}
#[allow(clippy::type_complexity)]
fn verify_votes(
votes: Vec<Transaction>,
labels: Vec<CrdsValueLabel>,
) -> (Vec<Transaction>, Vec<(CrdsValueLabel, Slot, Packets)>) {
let mut msgs = packet::to_packets_chunked(&votes, 1);
sigverify::ed25519_verify_cpu(&mut msgs);
) -> (Vec<Transaction>, Vec<(CrdsValueLabel, Packets)>) {
let msgs = packet::to_packets_chunked(&votes, 1);
let r = sigverify::ed25519_verify_cpu(&msgs);
let (vote_txs, packets) = izip!(labels.into_iter(), votes.into_iter(), msgs,)
.filter_map(|(label, vote, packet)| {
let slot = vote_transaction::parse_vote_transaction(&vote)
.and_then(|(_, vote, _)| vote.slots.last().copied())?;
assert_eq!(
r.iter()
.map(|packets_results| packets_results.len())
.sum::<usize>(),
votes.len()
);
// to_packets_chunked() above split into 1 packet long chunks
assert_eq!(packet.packets.len(), 1);
if !packet.packets[0].meta.discard {
Some((vote, (label, slot, packet)))
} else {
None
}
})
.unzip();
let (vote_txs, packets) = izip!(
labels.into_iter(),
votes.into_iter(),
r.iter().flatten(),
msgs,
)
.filter_map(|(label, vote, verify_result, packet)| {
if *verify_result != 0 {
Some((vote, (label, packet)))
} else {
None
}
})
.unzip();
(vote_txs, packets)
}
@@ -400,9 +397,7 @@ impl ClusterInfoVoteListener {
if let Some(bank) = bank {
let last_version = bank.last_vote_sync.load(Ordering::Relaxed);
let (new_version, msgs) = verified_vote_packets.get_latest_votes(last_version);
inc_new_counter_info!("bank_send_loop_batch_size", msgs.packets.len());
inc_new_counter_info!("bank_send_loop_num_batches", 1);
verified_packets_sender.send(vec![msgs])?;
verified_packets_sender.send(msgs)?;
#[allow(deprecated)]
bank.last_vote_sync.compare_and_swap(
last_version,
@@ -415,7 +410,6 @@ impl ClusterInfoVoteListener {
}
}
#[allow(clippy::too_many_arguments)]
fn process_votes_loop(
exit: Arc<AtomicBool>,
gossip_vote_txs_receiver: VerifiedVoteTransactionsReceiver,
@@ -426,12 +420,10 @@ impl ClusterInfoVoteListener {
replay_votes_receiver: ReplayVoteReceiver,
blockstore: Arc<Blockstore>,
bank_notification_sender: Option<BankNotificationSender>,
cluster_confirmed_slot_sender: GossipDuplicateConfirmedSlotsSender,
) -> Result<()> {
let mut confirmation_verifier =
OptimisticConfirmationVerifier::new(bank_forks.read().unwrap().root());
let mut last_process_root = Instant::now();
let cluster_confirmed_slot_sender = Some(cluster_confirmed_slot_sender);
loop {
if exit.load(Ordering::Relaxed) {
return Ok(());
@@ -460,12 +452,10 @@ impl ClusterInfoVoteListener {
&verified_vote_sender,
&replay_votes_receiver,
&bank_notification_sender,
&cluster_confirmed_slot_sender,
);
match confirmed_slots {
Ok(confirmed_slots) => {
confirmation_verifier
.add_new_optimistic_confirmed_slots(confirmed_slots.clone());
confirmation_verifier.add_new_optimistic_confirmed_slots(confirmed_slots);
}
Err(e) => match e {
Error::CrossbeamRecvTimeoutError(RecvTimeoutError::Timeout)
@@ -486,7 +476,7 @@ impl ClusterInfoVoteListener {
subscriptions: &RpcSubscriptions,
verified_vote_sender: &VerifiedVoteSender,
replay_votes_receiver: &ReplayVoteReceiver,
) -> Result<ThresholdConfirmedSlots> {
) -> Result<Vec<(Slot, Hash)>> {
Self::listen_and_confirm_votes(
gossip_vote_txs_receiver,
vote_tracker,
@@ -495,7 +485,6 @@ impl ClusterInfoVoteListener {
verified_vote_sender,
replay_votes_receiver,
&None,
&None,
)
}
@@ -507,8 +496,7 @@ impl ClusterInfoVoteListener {
verified_vote_sender: &VerifiedVoteSender,
replay_votes_receiver: &ReplayVoteReceiver,
bank_notification_sender: &Option<BankNotificationSender>,
cluster_confirmed_slot_sender: &Option<GossipDuplicateConfirmedSlotsSender>,
) -> Result<ThresholdConfirmedSlots> {
) -> Result<Vec<(Slot, Hash)>> {
let mut sel = Select::new();
sel.recv(gossip_vote_txs_receiver);
sel.recv(replay_votes_receiver);
@@ -537,7 +525,6 @@ impl ClusterInfoVoteListener {
subscriptions,
verified_vote_sender,
bank_notification_sender,
cluster_confirmed_slot_sender,
));
} else {
remaining_wait_time = remaining_wait_time
@@ -556,10 +543,9 @@ impl ClusterInfoVoteListener {
subscriptions: &RpcSubscriptions,
verified_vote_sender: &VerifiedVoteSender,
diff: &mut HashMap<Slot, HashMap<Pubkey, bool>>,
new_optimistic_confirmed_slots: &mut ThresholdConfirmedSlots,
new_optimistic_confirmed_slots: &mut Vec<(Slot, Hash)>,
is_gossip_vote: bool,
bank_notification_sender: &Option<BankNotificationSender>,
cluster_confirmed_slot_sender: &Option<GossipDuplicateConfirmedSlotsSender>,
) {
if vote.slots.is_empty() {
return;
@@ -595,7 +581,7 @@ impl ClusterInfoVoteListener {
// Fast track processing of the last slot in a vote transactions
// so that notifications for optimistic confirmation can be sent
// as soon as possible.
let (reached_threshold_results, is_new) = Self::track_optimistic_confirmation_vote(
let (is_confirmed, is_new) = Self::track_optimistic_confirmation_vote(
vote_tracker,
last_vote_slot,
last_vote_hash,
@@ -604,12 +590,7 @@ impl ClusterInfoVoteListener {
total_stake,
);
if reached_threshold_results[0] {
if let Some(sender) = cluster_confirmed_slot_sender {
let _ = sender.send(vec![(last_vote_slot, last_vote_hash)]);
}
}
if reached_threshold_results[1] {
if is_confirmed {
new_optimistic_confirmed_slots.push((last_vote_slot, last_vote_hash));
// Notify subscribers about new optimistic confirmation
if let Some(sender) = bank_notification_sender {
@@ -693,8 +674,7 @@ impl ClusterInfoVoteListener {
subscriptions: &RpcSubscriptions,
verified_vote_sender: &VerifiedVoteSender,
bank_notification_sender: &Option<BankNotificationSender>,
cluster_confirmed_slot_sender: &Option<GossipDuplicateConfirmedSlotsSender>,
) -> ThresholdConfirmedSlots {
) -> Vec<(Slot, Hash)> {
let mut diff: HashMap<Slot, HashMap<Pubkey, bool>> = HashMap::new();
let mut new_optimistic_confirmed_slots = vec![];
@@ -721,7 +701,6 @@ impl ClusterInfoVoteListener {
&mut new_optimistic_confirmed_slots,
is_gossip,
bank_notification_sender,
cluster_confirmed_slot_sender,
);
}
@@ -781,14 +760,14 @@ impl ClusterInfoVoteListener {
pubkey: Pubkey,
stake: u64,
total_epoch_stake: u64,
) -> (Vec<bool>, bool) {
) -> (bool, bool) {
let slot_tracker = vote_tracker.get_or_insert_slot_tracker(slot);
// Insert vote and check for optimistic confirmation
let mut w_slot_tracker = slot_tracker.write().unwrap();
w_slot_tracker
.get_or_insert_optimistic_votes_tracker(hash)
.add_vote_pubkey(pubkey, stake, total_epoch_stake, &THRESHOLDS_TO_CHECK)
.add_vote_pubkey(pubkey, stake, total_epoch_stake)
}
fn sum_stake(sum: &mut u64, epoch_stakes: Option<&EpochStakes>, pubkey: &Pubkey) {
@@ -1030,7 +1009,6 @@ mod tests {
&verified_vote_sender,
&replay_votes_receiver,
&None,
&None,
)
.unwrap();
@@ -1060,7 +1038,6 @@ mod tests {
&verified_vote_sender,
&replay_votes_receiver,
&None,
&None,
)
.unwrap();
@@ -1139,7 +1116,6 @@ mod tests {
&verified_vote_sender,
&replay_votes_receiver,
&None,
&None,
)
.unwrap();
@@ -1259,7 +1235,6 @@ mod tests {
&verified_vote_sender,
&replay_votes_receiver,
&None,
&None,
)
.unwrap();
@@ -1355,7 +1330,6 @@ mod tests {
&verified_vote_sender,
&replay_votes_receiver,
&None,
&None,
);
}
let slot_vote_tracker = vote_tracker.get_slot_vote_tracker(vote_slot).unwrap();
@@ -1500,7 +1474,6 @@ mod tests {
&subscriptions,
&verified_vote_sender,
&None,
&None,
);
// Setup next epoch
@@ -1555,7 +1528,6 @@ mod tests {
&subscriptions,
&verified_vote_sender,
&None,
&None,
);
}
@@ -1628,8 +1600,8 @@ mod tests {
assert!(packets.is_empty());
}
fn verify_packets_len(packets: &[(CrdsValueLabel, Slot, Packets)], ref_value: usize) {
let num_packets: usize = packets.iter().map(|(_, _, p)| p.packets.len()).sum();
fn verify_packets_len(packets: &[(CrdsValueLabel, Packets)], ref_value: usize) {
let num_packets: usize = packets.iter().map(|p| p.1.packets.len()).sum();
assert_eq!(num_packets, ref_value);
}

View File

@@ -1,751 +0,0 @@
use crate::{
fork_choice::ForkChoice, heaviest_subtree_fork_choice::HeaviestSubtreeForkChoice,
progress_map::ProgressMap,
};
use solana_sdk::{clock::Slot, hash::Hash};
use std::collections::{BTreeMap, HashMap, HashSet};
pub type GossipDuplicateConfirmedSlots = BTreeMap<Slot, Hash>;
type SlotStateHandler = fn(Slot, &Hash, Option<&Hash>, bool, bool) -> Vec<ResultingStateChange>;
#[derive(PartialEq, Debug)]
pub enum SlotStateUpdate {
Frozen,
DuplicateConfirmed,
Dead,
Duplicate,
}
#[derive(PartialEq, Debug)]
pub enum ResultingStateChange {
MarkSlotDuplicate,
RepairDuplicateConfirmedVersion(Hash),
DuplicateConfirmedSlotMatchesCluster,
}
impl SlotStateUpdate {
fn to_handler(&self) -> SlotStateHandler {
match self {
SlotStateUpdate::Dead => on_dead_slot,
SlotStateUpdate::Frozen => on_frozen_slot,
SlotStateUpdate::DuplicateConfirmed => on_cluster_update,
SlotStateUpdate::Duplicate => on_cluster_update,
}
}
}
fn repair_correct_version(_slot: Slot, _hash: &Hash) {}
fn on_dead_slot(
slot: Slot,
bank_frozen_hash: &Hash,
cluster_duplicate_confirmed_hash: Option<&Hash>,
_is_slot_duplicate: bool,
is_dead: bool,
) -> Vec<ResultingStateChange> {
assert!(is_dead);
// Bank should not have been frozen if the slot was marked dead
assert_eq!(*bank_frozen_hash, Hash::default());
if let Some(cluster_duplicate_confirmed_hash) = cluster_duplicate_confirmed_hash {
// If the cluster duplicate_confirmed some version of this slot, then
// there's another version
warn!(
"Cluster duplicate_confirmed slot {} with hash {}, but we marked slot dead",
slot, cluster_duplicate_confirmed_hash
);
// No need to check `is_slot_duplicate` and modify fork choice as dead slots
// are never frozen, and thus never added to fork choice. The state change for
// `MarkSlotDuplicate` will try to modify fork choice, but won't find the slot
// in the fork choice tree, so is equivalent to a
return vec![
ResultingStateChange::MarkSlotDuplicate,
ResultingStateChange::RepairDuplicateConfirmedVersion(
*cluster_duplicate_confirmed_hash,
),
];
}
vec![]
}
fn on_frozen_slot(
slot: Slot,
bank_frozen_hash: &Hash,
cluster_duplicate_confirmed_hash: Option<&Hash>,
is_slot_duplicate: bool,
is_dead: bool,
) -> Vec<ResultingStateChange> {
// If a slot is marked frozen, the bank hash should not be default,
// and the slot should not be dead
assert!(*bank_frozen_hash != Hash::default());
assert!(!is_dead);
if let Some(cluster_duplicate_confirmed_hash) = cluster_duplicate_confirmed_hash {
// If the cluster duplicate_confirmed some version of this slot, then
// confirm our version agrees with the cluster,
if cluster_duplicate_confirmed_hash != bank_frozen_hash {
// If the versions do not match, modify fork choice rule
// to exclude our version from being voted on and also
// repair correct version
warn!(
"Cluster duplicate_confirmed slot {} with hash {}, but we froze slot with hash {}",
slot, cluster_duplicate_confirmed_hash, bank_frozen_hash
);
return vec![
ResultingStateChange::MarkSlotDuplicate,
ResultingStateChange::RepairDuplicateConfirmedVersion(
*cluster_duplicate_confirmed_hash,
),
];
} else {
// If the versions match, then add the slot to the candidate
// set to account for the case where it was removed earlier
// by the `on_duplicate_slot()` handler
return vec![ResultingStateChange::DuplicateConfirmedSlotMatchesCluster];
}
}
if is_slot_duplicate {
// If we detected a duplicate, but have not yet seen any version
// of the slot duplicate_confirmed (i.e. block above did not execute), then
// remove the slot from fork choice until we get confirmation.
// If we get here, we either detected duplicate from
// 1) WindowService
// 2) A gossip duplicate_confirmed version that didn't match our frozen
// version.
// In both cases, mark the progress map for this slot as duplicate
return vec![ResultingStateChange::MarkSlotDuplicate];
}
vec![]
}
// Called when we receive either:
// 1) A duplicate slot signal from WindowStage,
// 2) Confirmation of a slot by observing votes from replay or gossip.
//
// This signals external information about this slot, which affects
// this validator's understanding of the validity of this slot
fn on_cluster_update(
slot: Slot,
bank_frozen_hash: &Hash,
cluster_duplicate_confirmed_hash: Option<&Hash>,
is_slot_duplicate: bool,
is_dead: bool,
) -> Vec<ResultingStateChange> {
if is_dead {
on_dead_slot(
slot,
bank_frozen_hash,
cluster_duplicate_confirmed_hash,
is_slot_duplicate,
is_dead,
)
} else if *bank_frozen_hash != Hash::default() {
// This case is mutually exclusive with is_dead case above because if a slot is dead,
// it cannot have been frozen, and thus cannot have a non-default bank hash.
on_frozen_slot(
slot,
bank_frozen_hash,
cluster_duplicate_confirmed_hash,
is_slot_duplicate,
is_dead,
)
} else {
vec![]
}
}
fn get_cluster_duplicate_confirmed_hash<'a>(
slot: Slot,
gossip_duplicate_confirmed_hash: Option<&'a Hash>,
local_frozen_hash: &'a Hash,
is_local_replay_duplicate_confirmed: bool,
) -> Option<&'a Hash> {
let local_duplicate_confirmed_hash = if is_local_replay_duplicate_confirmed {
// If local replay has duplicate_confirmed this slot, this slot must have
// descendants with votes for this slot, hence this slot must be
// frozen.
assert!(*local_frozen_hash != Hash::default());
Some(local_frozen_hash)
} else {
None
};
match (
local_duplicate_confirmed_hash,
gossip_duplicate_confirmed_hash,
) {
(Some(local_duplicate_confirmed_hash), Some(gossip_duplicate_confirmed_hash)) => {
if local_duplicate_confirmed_hash != gossip_duplicate_confirmed_hash {
error!(
"For slot {}, the gossip duplicate confirmed hash {}, is not equal
to the confirmed hash we replayed: {}",
slot, gossip_duplicate_confirmed_hash, local_duplicate_confirmed_hash
);
}
Some(&local_frozen_hash)
}
(Some(local_frozen_hash), None) => Some(local_frozen_hash),
_ => gossip_duplicate_confirmed_hash,
}
}
fn apply_state_changes(
slot: Slot,
progress: &mut ProgressMap,
fork_choice: &mut HeaviestSubtreeForkChoice,
ancestors: &HashMap<Slot, HashSet<Slot>>,
descendants: &HashMap<Slot, HashSet<Slot>>,
state_changes: Vec<ResultingStateChange>,
) {
for state_change in state_changes {
match state_change {
ResultingStateChange::MarkSlotDuplicate => {
progress.set_unconfirmed_duplicate_slot(
slot,
descendants.get(&slot).unwrap_or(&HashSet::default()),
);
fork_choice.mark_fork_invalid_candidate(slot);
}
ResultingStateChange::RepairDuplicateConfirmedVersion(
cluster_duplicate_confirmed_hash,
) => {
// TODO: Should consider moving the updating of the duplicate slots in the
// progress map from ReplayStage::confirm_forks to here.
repair_correct_version(slot, &cluster_duplicate_confirmed_hash);
}
ResultingStateChange::DuplicateConfirmedSlotMatchesCluster => {
progress.set_confirmed_duplicate_slot(
slot,
ancestors.get(&slot).unwrap_or(&HashSet::default()),
descendants.get(&slot).unwrap_or(&HashSet::default()),
);
fork_choice.mark_fork_valid_candidate(slot);
}
}
}
}
pub(crate) fn check_slot_agrees_with_cluster(
slot: Slot,
root: Slot,
frozen_hash: Option<Hash>,
gossip_duplicate_confirmed_slots: &GossipDuplicateConfirmedSlots,
ancestors: &HashMap<Slot, HashSet<Slot>>,
descendants: &HashMap<Slot, HashSet<Slot>>,
progress: &mut ProgressMap,
fork_choice: &mut HeaviestSubtreeForkChoice,
slot_state_update: SlotStateUpdate,
) {
if slot <= root {
return;
}
if frozen_hash.is_none() {
// If the bank doesn't even exist in BankForks yet,
// then there's nothing to do as replay of the slot
// hasn't even started
return;
}
let frozen_hash = frozen_hash.unwrap();
let gossip_duplicate_confirmed_hash = gossip_duplicate_confirmed_slots.get(&slot);
let is_local_replay_duplicate_confirmed = progress.is_duplicate_confirmed(slot).expect("If the frozen hash exists, then the slot must exist in bank forks and thus in progress map");
let cluster_duplicate_confirmed_hash = get_cluster_duplicate_confirmed_hash(
slot,
gossip_duplicate_confirmed_hash,
&frozen_hash,
is_local_replay_duplicate_confirmed,
);
let mut is_slot_duplicate =
progress.is_unconfirmed_duplicate(slot).expect("If the frozen hash exists, then the slot must exist in bank forks and thus in progress map");
if matches!(slot_state_update, SlotStateUpdate::Duplicate) {
if is_slot_duplicate {
// Already processed duplicate signal for this slot, no need to continue
return;
} else {
// Otherwise, mark the slot as duplicate so the appropriate state changes
// will trigger
is_slot_duplicate = true;
}
}
let is_dead = progress.is_dead(slot).expect("If the frozen hash exists, then the slot must exist in bank forks and thus in progress map");
let state_handler = slot_state_update.to_handler();
let state_changes = state_handler(
slot,
&frozen_hash,
cluster_duplicate_confirmed_hash,
is_slot_duplicate,
is_dead,
);
apply_state_changes(
slot,
progress,
fork_choice,
ancestors,
descendants,
state_changes,
);
}
#[cfg(test)]
mod test {
use super::*;
use crate::consensus::test::VoteSimulator;
use solana_runtime::bank_forks::BankForks;
use std::sync::RwLock;
use trees::tr;
struct InitialState {
heaviest_subtree_fork_choice: HeaviestSubtreeForkChoice,
progress: ProgressMap,
ancestors: HashMap<Slot, HashSet<Slot>>,
descendants: HashMap<Slot, HashSet<Slot>>,
slot: Slot,
bank_forks: RwLock<BankForks>,
}
fn setup() -> InitialState {
// Create simple fork 0 -> 1 -> 2 -> 3
let forks = tr(0) / (tr(1) / (tr(2) / tr(3)));
let mut vote_simulator = VoteSimulator::new(1);
vote_simulator.fill_bank_forks(forks, &HashMap::new());
let ancestors = vote_simulator.bank_forks.read().unwrap().ancestors();
let descendants = vote_simulator
.bank_forks
.read()
.unwrap()
.descendants()
.clone();
InitialState {
heaviest_subtree_fork_choice: vote_simulator.heaviest_subtree_fork_choice,
progress: vote_simulator.progress,
ancestors,
descendants,
slot: 0,
bank_forks: vote_simulator.bank_forks,
}
}
#[test]
fn test_frozen_duplicate() {
// Common state
let slot = 0;
let cluster_duplicate_confirmed_hash = None;
let is_dead = false;
// Slot is not detected as duplicate yet
let mut is_slot_duplicate = false;
// Simulate freezing the bank, add a
// new non-default hash, should return
// no actionable state changes yet
let bank_frozen_hash = Hash::new_unique();
assert!(on_frozen_slot(
slot,
&bank_frozen_hash,
cluster_duplicate_confirmed_hash,
is_slot_duplicate,
is_dead
)
.is_empty());
// Now mark the slot as duplicate, should
// trigger marking the slot as a duplicate
is_slot_duplicate = true;
assert_eq!(
on_cluster_update(
slot,
&bank_frozen_hash,
cluster_duplicate_confirmed_hash,
is_slot_duplicate,
is_dead
),
vec![ResultingStateChange::MarkSlotDuplicate]
);
}
#[test]
fn test_frozen_duplicate_confirmed() {
// Common state
let slot = 0;
let is_slot_duplicate = false;
let is_dead = false;
// No cluster duplicate_confirmed hash yet
let mut cluster_duplicate_confirmed_hash = None;
// Simulate freezing the bank, add a
// new non-default hash, should return
// no actionable state changes
let bank_frozen_hash = Hash::new_unique();
assert!(on_frozen_slot(
slot,
&bank_frozen_hash,
cluster_duplicate_confirmed_hash,
is_slot_duplicate,
is_dead
)
.is_empty());
// Now mark the same frozen slot hash as duplicate_confirmed by the cluster,
// should just confirm the slot
cluster_duplicate_confirmed_hash = Some(&bank_frozen_hash);
assert_eq!(
on_cluster_update(
slot,
&bank_frozen_hash,
cluster_duplicate_confirmed_hash,
is_slot_duplicate,
is_dead
),
vec![ResultingStateChange::DuplicateConfirmedSlotMatchesCluster,]
);
// If the cluster_duplicate_confirmed_hash does not match, then we
// should trigger marking the slot as a duplicate, and also
// try to repair correct version
let mismatched_hash = Hash::new_unique();
cluster_duplicate_confirmed_hash = Some(&mismatched_hash);
assert_eq!(
on_cluster_update(
slot,
&bank_frozen_hash,
cluster_duplicate_confirmed_hash,
is_slot_duplicate,
is_dead
),
vec![
ResultingStateChange::MarkSlotDuplicate,
ResultingStateChange::RepairDuplicateConfirmedVersion(mismatched_hash),
]
);
}
#[test]
fn test_duplicate_frozen_duplicate_confirmed() {
// Common state
let slot = 0;
let is_dead = false;
let is_slot_duplicate = true;
// Bank is not frozen yet
let mut cluster_duplicate_confirmed_hash = None;
let mut bank_frozen_hash = Hash::default();
// Mark the slot as duplicate. Because our version of the slot is not
// frozen yet, we don't know which version we have, so no action is
// taken.
assert!(on_cluster_update(
slot,
&bank_frozen_hash,
cluster_duplicate_confirmed_hash,
is_slot_duplicate,
is_dead
)
.is_empty());
// Freeze the bank, should now mark the slot as duplicate since we have
// not seen confirmation yet.
bank_frozen_hash = Hash::new_unique();
assert_eq!(
on_cluster_update(
slot,
&bank_frozen_hash,
cluster_duplicate_confirmed_hash,
is_slot_duplicate,
is_dead
),
vec![ResultingStateChange::MarkSlotDuplicate,]
);
// If the cluster_duplicate_confirmed_hash matches, we just confirm
// the slot
cluster_duplicate_confirmed_hash = Some(&bank_frozen_hash);
assert_eq!(
on_cluster_update(
slot,
&bank_frozen_hash,
cluster_duplicate_confirmed_hash,
is_slot_duplicate,
is_dead
),
vec![ResultingStateChange::DuplicateConfirmedSlotMatchesCluster,]
);
// If the cluster_duplicate_confirmed_hash does not match, then we
// should trigger marking the slot as a duplicate, and also
// try to repair correct version
let mismatched_hash = Hash::new_unique();
cluster_duplicate_confirmed_hash = Some(&mismatched_hash);
assert_eq!(
on_cluster_update(
slot,
&bank_frozen_hash,
cluster_duplicate_confirmed_hash,
is_slot_duplicate,
is_dead
),
vec![
ResultingStateChange::MarkSlotDuplicate,
ResultingStateChange::RepairDuplicateConfirmedVersion(mismatched_hash),
]
);
}
#[test]
fn test_duplicate_duplicate_confirmed() {
let slot = 0;
let correct_hash = Hash::new_unique();
let cluster_duplicate_confirmed_hash = Some(&correct_hash);
let is_dead = false;
// Bank is not frozen yet
let bank_frozen_hash = Hash::default();
// Because our version of the slot is not frozen yet, then even though
// the cluster has duplicate_confirmed a hash, we don't know which version we
// have, so no action is taken.
let is_slot_duplicate = true;
assert!(on_cluster_update(
slot,
&bank_frozen_hash,
cluster_duplicate_confirmed_hash,
is_slot_duplicate,
is_dead
)
.is_empty());
}
#[test]
fn test_duplicate_dead() {
let slot = 0;
let cluster_duplicate_confirmed_hash = None;
let is_dead = true;
// Bank is not frozen yet
let bank_frozen_hash = Hash::default();
// Even though our version of the slot is dead, the cluster has not
// duplicate_confirmed a hash, we don't know which version we have, so no action
// is taken.
let is_slot_duplicate = true;
assert!(on_cluster_update(
slot,
&bank_frozen_hash,
cluster_duplicate_confirmed_hash,
is_slot_duplicate,
is_dead
)
.is_empty());
}
#[test]
fn test_duplicate_confirmed_dead_duplicate() {
let slot = 0;
let correct_hash = Hash::new_unique();
// Cluster has duplicate_confirmed some version of the slot
let cluster_duplicate_confirmed_hash = Some(&correct_hash);
// Our version of the slot is dead
let is_dead = true;
let bank_frozen_hash = Hash::default();
// Even if the duplicate signal hasn't come in yet,
// we can deduce the slot is duplicate AND we have,
// the wrong version, so should mark the slot as duplicate,
// and repair the correct version
let mut is_slot_duplicate = false;
assert_eq!(
on_cluster_update(
slot,
&bank_frozen_hash,
cluster_duplicate_confirmed_hash,
is_slot_duplicate,
is_dead
),
vec![
ResultingStateChange::MarkSlotDuplicate,
ResultingStateChange::RepairDuplicateConfirmedVersion(correct_hash),
]
);
// If the duplicate signal comes in, nothing should change
is_slot_duplicate = true;
assert_eq!(
on_cluster_update(
slot,
&bank_frozen_hash,
cluster_duplicate_confirmed_hash,
is_slot_duplicate,
is_dead
),
vec![
ResultingStateChange::MarkSlotDuplicate,
ResultingStateChange::RepairDuplicateConfirmedVersion(correct_hash),
]
);
}
#[test]
fn test_apply_state_changes() {
// Common state
let InitialState {
mut heaviest_subtree_fork_choice,
mut progress,
ancestors,
descendants,
slot,
..
} = setup();
// MarkSlotDuplicate should mark progress map and remove
// the slot from fork choice
apply_state_changes(
slot,
&mut progress,
&mut heaviest_subtree_fork_choice,
&ancestors,
&descendants,
vec![ResultingStateChange::MarkSlotDuplicate],
);
assert!(!heaviest_subtree_fork_choice
.is_candidate_slot(slot)
.unwrap());
for child_slot in descendants
.get(&slot)
.unwrap()
.iter()
.chain(std::iter::once(&slot))
{
assert_eq!(
progress
.latest_unconfirmed_duplicate_ancestor(*child_slot)
.unwrap(),
slot
);
}
// DuplicateConfirmedSlotMatchesCluster should re-enable fork choice
apply_state_changes(
slot,
&mut progress,
&mut heaviest_subtree_fork_choice,
&ancestors,
&descendants,
vec![ResultingStateChange::DuplicateConfirmedSlotMatchesCluster],
);
for child_slot in descendants
.get(&slot)
.unwrap()
.iter()
.chain(std::iter::once(&slot))
{
assert!(progress
.latest_unconfirmed_duplicate_ancestor(*child_slot)
.is_none());
}
assert!(heaviest_subtree_fork_choice
.is_candidate_slot(slot)
.unwrap());
}
#[test]
fn test_state_ancestor_confirmed_descendant_duplicate() {
// Common state
let InitialState {
mut heaviest_subtree_fork_choice,
mut progress,
ancestors,
descendants,
bank_forks,
..
} = setup();
assert_eq!(heaviest_subtree_fork_choice.best_overall_slot(), 3);
let root = 0;
let mut gossip_duplicate_confirmed_slots = GossipDuplicateConfirmedSlots::default();
// Mark slot 2 as duplicate confirmed
let slot2_hash = bank_forks.read().unwrap().get(2).unwrap().hash();
gossip_duplicate_confirmed_slots.insert(2, slot2_hash);
check_slot_agrees_with_cluster(
2,
root,
Some(slot2_hash),
&gossip_duplicate_confirmed_slots,
&ancestors,
&descendants,
&mut progress,
&mut heaviest_subtree_fork_choice,
SlotStateUpdate::DuplicateConfirmed,
);
assert_eq!(heaviest_subtree_fork_choice.best_overall_slot(), 3);
// Mark 3 as duplicate, should not remove slot 2 from fork choice
check_slot_agrees_with_cluster(
3,
root,
Some(bank_forks.read().unwrap().get(3).unwrap().hash()),
&gossip_duplicate_confirmed_slots,
&ancestors,
&descendants,
&mut progress,
&mut heaviest_subtree_fork_choice,
SlotStateUpdate::Duplicate,
);
assert_eq!(heaviest_subtree_fork_choice.best_overall_slot(), 2);
}
#[test]
fn test_state_ancestor_duplicate_descendant_confirmed() {
// Common state
let InitialState {
mut heaviest_subtree_fork_choice,
mut progress,
ancestors,
descendants,
bank_forks,
..
} = setup();
assert_eq!(heaviest_subtree_fork_choice.best_overall_slot(), 3);
let root = 0;
let mut gossip_duplicate_confirmed_slots = GossipDuplicateConfirmedSlots::default();
// Mark 2 as duplicate confirmed
check_slot_agrees_with_cluster(
2,
root,
Some(bank_forks.read().unwrap().get(2).unwrap().hash()),
&gossip_duplicate_confirmed_slots,
&ancestors,
&descendants,
&mut progress,
&mut heaviest_subtree_fork_choice,
SlotStateUpdate::Duplicate,
);
assert_eq!(heaviest_subtree_fork_choice.best_overall_slot(), 1);
// Mark slot 3 as duplicate confirmed, should mark slot 2 as duplicate confirmed as well
let slot3_hash = bank_forks.read().unwrap().get(3).unwrap().hash();
gossip_duplicate_confirmed_slots.insert(3, slot3_hash);
check_slot_agrees_with_cluster(
3,
root,
Some(slot3_hash),
&gossip_duplicate_confirmed_slots,
&ancestors,
&descendants,
&mut progress,
&mut heaviest_subtree_fork_choice,
SlotStateUpdate::DuplicateConfirmed,
);
assert_eq!(heaviest_subtree_fork_choice.best_overall_slot(), 3);
}
}

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