Compare commits

..

212 Commits

Author SHA1 Message Date
Tyera Eulberg
39a4cc95dc v1.9: Impl get_/set_return_data syscalls for ProgramTest (#22652)
* Remove &mut self from set_return_data

* Impl get_/set_return_data for program-test SyscallStubs

* Add return_data program-test
2022-01-21 18:03:27 -07:00
mergify[bot]
187ed6a387 Remove unused fields from Bank (backport #22491) (#22630)
* Remove unused fields from Bank (#22491)

(cherry picked from commit 9977396d8f)

# Conflicts:
#	runtime/src/serde_snapshot/future.rs

* fixup the backport

Co-authored-by: Brooks Prumo <brooks@solana.com>
2022-01-22 00:13:32 +00:00
mergify[bot]
91bc44931f Add hidden cli option to allow validator reports replayed transaction cost metrics (backport #22369) (#22519)
* Add hidden cli option to allow validator reports replayed transaction cost metrics (#22369)

* add hidden cli option to allow validator reports replayed transaction cost detail metrics

* Update validator/src/main.rs

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

* - rebase master, using unbounded instead of channel; dowgrade to datapoint_trace

* removed cli arg, prefer log at trace

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

# Conflicts:
#	core/src/tvu.rs

* fix conflict

Co-authored-by: Tao Zhu <82401714+taozhu-chicago@users.noreply.github.com>
Co-authored-by: Tao Zhu <tao@solana.com>
2022-01-21 15:05:41 -07:00
mergify[bot]
35ca3182ba Add estimated and actual block cost units metrics (backport #22326) (#22517)
* Add estimated and actual block cost units metrics (#22326)

* - report cost details for transactions selected to be packed into block;
- report estimated execution units packed into block, and actual units and time after execution

* revert reporting per-transaction details

* rollup transaction cost details (eg signature cost, wirte lock, data cost and execution costs) into block stats

* change naming from units to cu, use struct to replace tuple

(cherry picked from commit 1309a9cea0)

# Conflicts:
#	core/src/banking_stage.rs
#	core/src/qos_service.rs

* fix conflicts

Co-authored-by: Tao Zhu <82401714+taozhu-chicago@users.noreply.github.com>
Co-authored-by: Tao Zhu <tao@solana.com>
2022-01-21 15:05:19 -07:00
mergify[bot]
24345d8e63 Update introduction.md (#22623) (#22625)
A few fixes for grammatical and spelling issues.

(cherry picked from commit 373f200ab8)

Co-authored-by: filip <44206832+filipkujawa@users.noreply.github.com>
2022-01-21 13:31:47 -07:00
anatoly yakovenko
bf45f5b88e Faster dedup v1.9 (#22638)
Faster dedup port of #22607
2022-01-21 11:21:28 -08:00
mergify[bot]
2ddb5b27c1 Refactor: move instructions sysvar serialization out of Message (#22544) (#22595)
(cherry picked from commit 7ba57e7a7c)

Co-authored-by: Justin Starry <justin@solana.com>
2022-01-21 13:45:47 +08:00
mergify[bot]
7f10fd6a21 Refactor: move compute budget runtime logic into solana-program-runtime (backport #22543) (#22545)
* Refactor: move compute budget runtime logic into solana-program-runtime (#22543)

(cherry picked from commit cc76a73c49)

# Conflicts:
#	programs/bpf/tests/programs.rs
#	sdk/src/compute_budget.rs

* resolve conflicts

Co-authored-by: Justin Starry <justin@solana.com>
2022-01-21 13:45:01 +08:00
mergify[bot]
a0a881594a Speed up packet dedup and fix benches (#22592) (#22613)
* Speed up packet dedup and fix benches

* fix tests

* allow int arithmetic in bench

(cherry picked from commit a2d251ce1e)

Co-authored-by: Justin Starry <justin@solana.com>
2022-01-20 22:51:58 +00:00
mergify[bot]
e9e35fd7bd system-monitor-service: support percentages from bigger numbers (#22598)
(cherry picked from commit cca3dbc76d)

Co-authored-by: Trent Nelson <trent@solana.com>
2022-01-20 11:37:52 +00:00
Trent Nelson
66b94b86a9 banking-stage: remove unused stats fields 2022-01-20 06:09:10 +00:00
mergify[bot]
59f406d78a Refactor: move simple vote parsing to runtime (backport #22537) (#22587)
* Refactor: move simple vote parsing to runtime (#22537)

(cherry picked from commit 7f20c6149e)

# Conflicts:
#	core/src/cluster_info_vote_listener.rs
#	core/src/verified_vote_packets.rs
#	programs/vote/src/vote_transaction.rs
#	rpc/src/rpc_subscriptions.rs
#	runtime/src/bank.rs
#	runtime/src/bank_utils.rs
#	runtime/src/vote_sender_types.rs

* resolve conflicts

Co-authored-by: Justin Starry <justin@solana.com>
2022-01-20 04:51:50 +00:00
mergify[bot]
dbf9a32883 Optimize packet dedup (#22571) (#22585)
* Use bloom filter to dedup packets

* dedup first

* Update bloom/src/bloom.rs

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

* Update core/src/sigverify_stage.rs

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

* Update core/src/sigverify_stage.rs

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

* Update core/src/sigverify_stage.rs

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

* fixup

* fixup

* fixup

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

# Conflicts:
#	Cargo.lock
#	core/Cargo.toml
#	core/src/banking_stage.rs
#	core/src/sigverify_stage.rs
#	gossip/Cargo.toml
#	perf/Cargo.toml
#	programs/bpf/Cargo.lock
#	runtime/Cargo.toml

Co-authored-by: anatoly yakovenko <anatoly@solana.com>
2022-01-20 02:51:49 +00:00
mergify[bot]
37e9076db0 Add PacketBatch packet_indexes stat (#22564) (#22575)
* collect stats on packet batch indicies

* cleanup

* cleanup

* cleanup

* change name

(cherry picked from commit 650882217c)

# Conflicts:
#	core/src/banking_stage.rs

Co-authored-by: buffalu <85544055+buffalu@users.noreply.github.com>
2022-01-20 00:05:05 +00:00
mergify[bot]
f77ea5f324 improves sigverify discard_excess_packets performance (backport #22577) (#22580)
* improves sigverify discard_excess_packets performance (#22577)

As shown by the added benchmark, current code does worse if there is a
spam address plus a lot of unique addresses.

on current master:
test bench_packet_discard_many_senders  ... bench:   1,997,960 ns/iter (+/- 103,715)
test bench_packet_discard_mixed_senders ... bench:  14,256,116 ns/iter (+/- 534,865)
test bench_packet_discard_single_sender ... bench:   1,306,809 ns/iter (+/- 61,992)

with this commit:
test bench_packet_discard_many_senders  ... bench:   1,644,025 ns/iter (+/- 83,715)
test bench_packet_discard_mixed_senders ... bench:   1,089,789 ns/iter (+/- 86,324)
test bench_packet_discard_single_sender ... bench:     955,234 ns/iter (+/- 55,953)

(cherry picked from commit dcf44d2523)

# Conflicts:
#	core/src/sigverify_stage.rs

* removes mergify merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2022-01-19 20:14:10 +00:00
mergify[bot]
c9df037dae Track discard time of excess packets in sigverify (#22554) (#22570)
* discard time histogram

* closer to the if

* update

(cherry picked from commit e616a7ebfc)

Co-authored-by: anatoly yakovenko <anatoly@solana.com>
2022-01-19 01:52:30 +00:00
mergify[bot]
2b87d99479 Use VecDeque instead of Vec in sigverify stage (#22538) (#22550)
avoid bad performance of remove(0) for a single sender

(cherry picked from commit 49443406fd)

# Conflicts:
#	core/src/sigverify_stage.rs

Co-authored-by: sakridge <sakridge@gmail.com>
2022-01-19 01:46:34 +00:00
mergify[bot]
2546ef4ad6 metrics for generate new bank forks (#22492) (#22548)
* metrics for generate new bank forks

* fixed

* Apply suggestions from code review

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

* --fixup

* fixup!

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

# Conflicts:
#	core/src/replay_stage.rs

Co-authored-by: anatoly yakovenko <anatoly@solana.com>
2022-01-19 01:45:25 +00:00
mergify[bot]
96ae795758 Add more details about vote account key rotation (#22539)
(cherry picked from commit 901b2881fb)

Co-authored-by: Michael Vines <mvines@gmail.com>
2022-01-17 09:16:25 +00:00
Michael Vines
9bddb4e437 vote account withdraw authority may change the authorized voter 2022-01-15 23:46:10 -08:00
mergify[bot]
4079f12a3e Perf: Store deserialized sysvars in the sysvars cache (backport #22455) (#22480)
* Perf: Store deserialized sysvars in the sysvars cache (#22455)

* Perf: Store deserialized sysvars in sysvars cache

* add bench

* resolve conflicts

Co-authored-by: Justin Starry <justin@solana.com>
2022-01-15 08:48:34 +00:00
mergify[bot]
e121b94524 Bugfix/block subscribe (#22516) (#22525)
* use correct operation name

* require enable_rpc_transaction_history flag when enabling block_subscription

Co-authored-by: Zano <segfaultdoctor@protonmail.com>
(cherry picked from commit 7171b3a3ac)

Co-authored-by: segfaultdoctor <zano@jito.wtf>
2022-01-15 05:05:21 +00:00
mergify[bot]
a7623ad18c Fetch sysvars from invoke context for vote program (backport #22444) (#22469)
* Fetch sysvars from invoke context for vote program (#22444)

* resolve conflicts

Co-authored-by: Justin Starry <justin@solana.com>
2022-01-15 03:56:00 +00:00
Tao Zhu
054e475c6c ABI changed - added two more vote_cost related fields to cost_tracker 2022-01-14 10:49:43 -06:00
Tao Zhu
7a421fe602 Port counting vote CUs to block cost to v1.9 2022-01-14 10:49:43 -06:00
mergify[bot]
2ef0b85829 docs: fix get fee for message docs (#22501) (#22504)
(cherry picked from commit f12a8fcd73)

Co-authored-by: Yihau Chen <a122092487@gmail.com>
2022-01-14 09:00:22 +00:00
mergify[bot]
a6b7a3b7ff Refactor: move sysvar cache to new module (backport #22448) (#22461)
* Refactor: move sysvar cache to new module

(cherry picked from commit 7171c95bdd)

# Conflicts:
#	Cargo.lock
#	program-runtime/Cargo.toml
#	program-runtime/src/invoke_context.rs
#	programs/bpf/Cargo.lock
#	programs/bpf_loader/src/syscalls.rs
#	programs/stake/src/stake_instruction.rs
#	programs/vote/src/vote_instruction.rs
#	runtime/src/message_processor.rs

* resolve conflicts

Co-authored-by: Justin Starry <justin@solana.com>
2022-01-14 08:43:26 +00:00
mergify[bot]
9d69f2b324 Bank::get_fee_for_message is now nonce aware (backport #22494) (#22499)
* `Bank::get_fee_for_message` is now nonce aware

(cherry picked from commit 4c577d7f8c)

# Conflicts:
#	runtime/src/bank.rs
#	sdk/program/src/message/sanitized.rs

* Resolve conflicts

Co-authored-by: Michael Vines <mvines@gmail.com>
2022-01-14 03:25:10 +00:00
mergify[bot]
4f82a4ba1f log internals (#22493) (#22497)
(cherry picked from commit eca8d21249)

Co-authored-by: carllin <carl@solana.com>
2022-01-14 02:33:36 +00:00
mergify[bot]
ed0b30efcc nit: Traceable balance checks (#22462) (#22489)
(cherry picked from commit 1632ee03da)

Co-authored-by: Jack May <jack@solana.com>
2022-01-13 19:09:00 +00:00
mergify[bot]
4ee6bc9a93 downgrade individual per-program-timing to trace to reduce writes to influx (#22471)
(cherry picked from commit 6614727be8)

Co-authored-by: Tao Zhu <tao@solana.com>
2022-01-13 02:37:47 +00:00
Lijun Wang
676c43b9d2 Fixed a merge issue (#22464)
Removed AddressLookupError
2022-01-12 13:56:39 -08:00
mergify[bot]
b1d8296498 Update docs vis-a-vis prohibition of RentPaying accounts (#22438) (#22458)
* Rent-exempt docs for exchange integrations

* Remove discussion of rent-paying accounts from developing docs

* Improve verbiage

(cherry picked from commit b27333e52d)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2022-01-12 19:58:05 +00:00
Tyera Eulberg
34984ed16e v1.9: Only examine explicit tx accounts for rent state (#22442)
* Add failing test

* Fix: only examine accounts explicitly included in a tx
2022-01-11 20:55:10 -07:00
mergify[bot]
f4d1577337 Refactor: consolidate memo extraction for each message version (#22422) (#22435)
(cherry picked from commit 35a5dd9c45)

Co-authored-by: Justin Starry <justin@solana.com>
2022-01-12 00:23:03 +00:00
mergify[bot]
58dcc451a9 Prevent rent-paying account creation (backport #22292) (#22428)
* Prevent rent-paying account creation (#22292)

* Fixup typo

* Add new feature

* Add new TransactionError

* Add framework for checking account state before and after transaction processing

* Fail transactions that leave new rent-paying accounts

* Only check rent-state of writable tx accounts

* Review comments: combine process_result success behavior; log and metrics before feature activation

* Fix tests that assume rent-exempt accounts are okay

* Remove test no longer relevant

* Remove native/sysvar special case

* Move metrics submission to report legacy->legacy rent paying transitions as well

(cherry picked from commit 637e366b18)

# Conflicts:
#	runtime/src/bank.rs
#	runtime/src/lib.rs

* Fix conflicts and rework for TransactionRefCells

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2022-01-11 23:17:03 +00:00
mergify[bot]
f0695ef6d9 optimizes ReadOnlyAccountsCache LRU eviction implementation (backport #22403) (#22426)
* optimizes ReadOnlyAccountsCache LRU eviction implementation (#22403)

ReadOnlyAccountsCache is using a background thread, table scan and sort
to implement LRU eviction policy:
https://github.com/solana-labs/solana/blob/eaa52bc93/runtime/src/read_only_accounts_cache.rs#L66-L73
https://github.com/solana-labs/solana/blob/eaa52bc93/runtime/src/read_only_accounts_cache.rs#L186-L191
https://github.com/solana-labs/solana/blob/eaa52bc93/runtime/src/read_only_accounts_cache.rs#L222

DashMap internally locks each shard when accessed; so a table scan in
the background thread can create a lot of lock contention.

This commit adds an index-list queue containing cached keys in the order
that they are accessed. Each hash-map entry also includes its index into
this queue.
When an item is first entered into the cache, it is added to the end of
the queue. Also each time an entry is looked up from the cache it is
moved to the end of queue. As a result, items in the queue are always
sorted in the order that they have last been accessed. When doing LRU
eviction, cache entries are evicted from the front of the queue.
Using index-list, all queue operations above are O(1) with low overhead
and so above achieves an efficient implementation of LRU cache eviction
policy.

(cherry picked from commit a49ef49f87)

# Conflicts:
#	Cargo.lock
#	programs/bpf/Cargo.lock
#	runtime/Cargo.toml
#	runtime/src/accounts_db.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2022-01-11 19:09:57 +00:00
mergify[bot]
41b0d6cca3 limits gossip vote stats to the top most voted slots (#22416) (#22418)
(cherry picked from commit 49da347d84)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2022-01-10 23:14:57 +00:00
mergify[bot]
ae77a52c97 wrap create executor timings datapoint in a module (#22398)
(cherry picked from commit 428575f9ae)

Co-authored-by: Trent Nelson <trent@solana.com>
2022-01-09 06:41:44 +00:00
mergify[bot]
133314e58c bank: fix executor cache metrics (#22396)
(cherry picked from commit 3b4aad9df1)

Co-authored-by: Trent Nelson <trent@solana.com>
2022-01-09 06:06:35 +00:00
Trent Nelson
cb49ae21b4 Bump version to v1.9.5 2022-01-08 21:17:51 +00:00
mergify[bot]
a9ebba5643 Clarify docs of minimum_balance (#22385) (#22387)
(cherry picked from commit 0f94e1d3a2)

Co-authored-by: Evan Conrad <evan@roomservice.dev>
2022-01-08 20:07:57 +00:00
mergify[bot]
8ce65878da improve multi executor cache addition (#22382)
Co-authored-by: Jack May <jack@solana.com>
2022-01-08 13:03:46 +00:00
Trent Nelson
a4ca18a54d add excutor creation trace timings 2022-01-08 05:25:37 -07:00
mergify[bot]
7cb147fdcd Executor cache count primer (backport #22333) (#22375)
* bank: prime new executor cache entry use-counts

(cherry picked from commit 4ce48307bb)

* --amend

(cherry picked from commit ad3cb0bc93)

Co-authored-by: Trent Nelson <trent@solana.com>
2022-01-08 11:01:34 +00:00
mergify[bot]
2d693be9fa remove per program timings from blockstore processor ledger replay (#22370) (#22372)
(cherry picked from commit 813006b33b)

Co-authored-by: carllin <carl@solana.com>
2022-01-08 08:43:48 +00:00
mergify[bot]
50e716fc80 bank: Add executors cache metrics (#22368)
(cherry picked from commit 6d76db1de5)

Co-authored-by: Trent Nelson <trent@solana.com>
2022-01-08 01:34:53 +00:00
Justin Starry
1f00926874 Add runtime support for address table lookups (backport #22223) (#22354) 2022-01-08 07:57:04 +08:00
mergify[bot]
662c6be51e removes CowCachedExecutors (#22343) (#22363)
Copy-on-write semantics for cached executors can be implemented by a
simple Arc<CachedExecutors> as opposed to CowCachedExecutors:
https://github.com/solana-labs/solana/blob/f1e2598ba/runtime/src/bank.rs#L244-L247

This will also avoid the need for double locking as in:
https://github.com/solana-labs/solana/blob/f1e2598ba/runtime/src/bank.rs#L3490-L3491
https://github.com/solana-labs/solana/blob/f1e2598ba/runtime/src/bank.rs#L3525-L3526

(cherry picked from commit c2389fc209)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2022-01-07 16:04:13 +00:00
mergify[bot]
9761f5b67f Add aarch64-apple-darwin publish tarball step (#22356)
(cherry picked from commit e2aa932e97)

Co-authored-by: Michael Vines <mvines@gmail.com>
2022-01-07 10:17:11 +00:00
mergify[bot]
7b1da62763 Add execute metrics (backport #22296) (#22335)
* move `ExecuteTimings` from `runtime::bank` to `program_runtime::timings`

(cherry picked from commit 7d32909e17)

# Conflicts:
#	core/Cargo.toml
#	ledger/Cargo.toml
#	programs/bpf/Cargo.lock

* Add execute metrics

(cherry picked from commit b25e4a200b)

* Add metrics for executor creation

(cherry picked from commit 848b6dfbdd)

* Add helper macro for `AddAssign`ing with saturating arithmetic

(cherry picked from commit deb9344e49)

* Use saturating_add_assign macro

(cherry picked from commit 72fc6096a0)

* Consolidate process instruction execution timings to own struct

(cherry picked from commit 390ef0fbcd)

Co-authored-by: Trent Nelson <trent@solana.com>
Co-authored-by: Carl Lin <carl@solana.com>
2022-01-07 09:11:18 +00:00
mergify[bot]
2f97fee71a Cleanup ledger-tool analyze-storage command (#22310) (#22352)
* Make ledger-tool analyze-storage use Blockstore::open()

Opening a large ledger may require setting a larger open file descriptor
limit. Blockstore::open() does this whereas the underlying Database
object that analyze-storage was opening does not.

* Move key_size call lookup to take advantage of traits

* Fix typo where analyze worked on wrong column

* Make analyze-storage analyze all columns

(cherry picked from commit 9f1f64e384)

Co-authored-by: steviez <steven@solana.com>
2022-01-07 07:47:27 +00:00
Justin Starry
3ae674dd28 Increase timeout of local-cluster-slow CI step 2022-01-07 15:31:10 +08:00
mergify[bot]
8214bc9db4 Retain executor cache counts (#22322) (#22341)
(cherry picked from commit f1e2598baa)

Co-authored-by: Jack May <jack@solana.com>
2022-01-06 19:00:29 +00:00
mergify[bot]
1132def37c Split up local cluster tests into separate CI steps (backport #22295) (#22303)
* Split up local cluster tests into separate CI steps (#22295)

* Split up local cluster tests into separate CI steps

* Update buildkite-pipeline.sh

(cherry picked from commit 0e1afcbb26)

# Conflicts:
#	local-cluster/tests/local_cluster.rs

* resolve conflicts

Co-authored-by: Justin Starry <justin@solana.com>
2022-01-06 17:02:45 +00:00
mergify[bot]
7267ebaaf2 Consume from AccountsDataMeter (backport #21994) (#22323)
* Consume from AccountsDataMeter (#21994)

(cherry picked from commit 1460f00e0f)

# Conflicts:
#	program-runtime/src/invoke_context.rs

* fixup! conflicts

* fix tests for v1.9

* fixup! clippy

Co-authored-by: Brooks Prumo <brooks@solana.com>
2022-01-06 17:01:02 +00:00
mergify[bot]
4be6e52a4f cache executors on failed transactions (backport #22308) (#22328)
* cache executors on failed transactions (#22308)

(cherry picked from commit 12e160269e)

# Conflicts:
#	program-runtime/src/invoke_context.rs
#	runtime/src/bank.rs

* resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
2022-01-06 09:14:48 +00:00
mergify[bot]
e7348243b4 [ledger-tool]compare_blocks (#22229) (#22330)
* 1.made load_credentials accept credential path as a parameter. 2.partial implement bigtable comparasion function

* finding missing blocks in bigtables in a specified range

* refactor compare-blocks,add unit test for missing_blocks and fmt

* compare-block fix last block bug

* refactor compare-block and improve wording

* Update ledger-tool/src/bigtable.rs

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

* update compare-block command-line description

* style:improve wording/naming/code style

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

Co-authored-by: pieceofr <komimi.p@gmail.com>
2022-01-06 08:55:26 +00:00
mergify[bot]
fc0c74d722 Only sum accounts data len from non-zero lamport accounts (#22309) (#22317)
(cherry picked from commit ab13e39518)

Co-authored-by: Brooks Prumo <brooks@solana.com>
2022-01-06 02:43:54 +00:00
mergify[bot]
687cd4779e Add AccountsDataMeter to InvokeContext (#21813) (#22299)
(cherry picked from commit 800472ddf5)

Co-authored-by: Brooks Prumo <brooks@solana.com>
2022-01-06 01:31:11 +00:00
mergify[bot]
b28d7050ab Update default --dynamic-port-range values to include some room for additional ports that may be added in the future (#22321)
(cherry picked from commit 37ebd9bd9e)

Co-authored-by: Michael Vines <mvines@gmail.com>
2022-01-06 01:29:06 +00:00
Michael Vines
6d72acfd6d --dynamic-port-range now requires at least 12 ports 2022-01-05 16:12:28 -08:00
Brooks Prumo
840ec0686e Fix broken build from bpf/tests/programs.rs (#22312)
These tests were broken due to PR #22289
2022-01-05 15:06:15 -06:00
Will Hickey
ba0188a36d Bump version to 1.9.4 (#22304) 2022-01-05 12:02:36 -06:00
mergify[bot]
05b9a2f203 fix(rpc): recreate dead and uncleaned subscriptions (#22281) (#22294)
(cherry picked from commit c1995c647b)

Co-authored-by: Nikita <bananaelecitrus@gmail.com>
2022-01-05 17:16:12 +00:00
mergify[bot]
8578429c4d Refactor: Improve type safety and readability of transaction execution (backport #22215) (#22289)
* Refactor: Improve type safety and readability of transaction execution (#22215)

* resolve conflicts

Co-authored-by: Justin Starry <justin@solana.com>
2022-01-05 23:01:15 +08:00
mergify[bot]
87f4a1f4b6 Bank gets accounts data len delta from MessageProcessor::process_message() (#22288)
(cherry picked from commit 635337d2ff)

Co-authored-by: Brooks Prumo <brooks@solana.com>
2022-01-05 05:50:03 +00:00
mergify[bot]
17411f9b4c Add accounts_data_len to Bank (#21781) (#22285)
(cherry picked from commit eeb97fe7ce)

Co-authored-by: Brooks Prumo <brooks@solana.com>
2022-01-05 02:24:52 +00:00
mergify[bot]
fb0e5adc7e patches bug in recv_mmsg when npkts != nrecv (backport #22276) (#22280)
* removes total-size from return value of recv_mmsg

(cherry picked from commit 4b24499916)

* patches bug in recv_mmsg when npkts != nrecv

If recv_mmsg receives 2 packets where the first one is filtered out,
then it returns npkts == 1:
https://github.com/solana-labs/solana/blob/01a096adc/streamer/src/recvmmsg.rs#L104-L115

But then streamer::packet::recv_from will erroneously keep the 1st
packet and drop the 2nd one:
https://github.com/solana-labs/solana/blob/01a096adc/streamer/src/packet.rs#L34-L49

To avoid this bug, this commit updates recv_mmsg to always return total
number of received packets. If socket address cannot be correctly
obtained, it is left as the default value which is UNSPECIFIED:
https://github.com/solana-labs/solana/blob/01a096adc/sdk/src/packet.rs#L145

(cherry picked from commit 379feecae5)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2022-01-04 23:42:52 +00:00
mergify[bot]
f4ded6fb6b Updates to the address lookup table proposal (#22269) (#22270)
Co-authored-by: Justin Starry <justin@solana.com>
2022-01-04 23:38:51 +00:00
mergify[bot]
f89bf7b939 Compute accounts data len during generate_index() (#21757) (#22277)
(cherry picked from commit ec7e17787e)

Co-authored-by: Brooks Prumo <brooks@solana.com>
2022-01-04 22:44:51 +00:00
mergify[bot]
c99aed4abf Update address map proposal to improve dev experience (#21576) (#22283)
* Update address map proposal to improve dev experience

* another revision to match implementation

(cherry picked from commit 0224a8b127)

Co-authored-by: Justin Starry <justin@solana.com>
2022-01-04 22:11:59 +00:00
mergify[bot]
edfd8c1717 Fix program log filtering (#22133) (#22151)
(cherry picked from commit c7b0917e1a)

Co-authored-by: Jack May <jack@solana.com>
2022-01-04 21:56:49 +00:00
mergify[bot]
09dbf069e8 Add test to enforce that program id account info for CPI is optional (#22069) (#22103)
* Update tests to demonstrate that program id account info for CPI is optional

* Clean up comments that say that program id account info is required

(cherry picked from commit ec7536faf6)

Co-authored-by: Justin Starry <justin@solana.com>
2022-01-04 21:47:48 +00:00
mergify[bot]
9764d4349b Add return types to generate_index() (#21735) (#22275)
(cherry picked from commit 1528f85112)

Co-authored-by: Brooks Prumo <brooks@solana.com>
2022-01-04 18:27:40 +00:00
mergify[bot]
d84b994451 shrinks size of Packet.Meta (backport #22224) (#22273)
* removes seed and slot fields from Packet.Meta

507367e6ac
updated window-service to send shreds (as opposed to packets) to
retransmit-stage and so seed and slot fields in Packet.Meta are unused:
https://github.com/solana-labs/solana/blob/d6ec103be/sdk/src/packet.rs#L27-L28

(cherry picked from commit aa9f7ed7e8)

* uses std::net::IpAddr type for Packet.Meta.addr

(cherry picked from commit 73a7741c49)

# Conflicts:
#	streamer/src/streamer.rs

* adds bitflags to Packet.Meta

Instead of a separate bool type for each flag, all the flags can be
encoded in a type-safe bitflags encoded in a single u8:
https://github.com/solana-labs/solana/blob/d6ec103be/sdk/src/packet.rs#L19-L31

(cherry picked from commit 01a096adc8)

# Conflicts:
#	sdk/Cargo.toml

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2022-01-04 17:38:29 +00:00
mergify[bot]
185f52b712 Lower vote-only-mode to 400 (#22210) (#22272)
(cherry picked from commit 2486e21ffe)

Co-authored-by: sakridge <sakridge@gmail.com>
2022-01-04 15:15:16 +00:00
mergify[bot]
3b59f67562 Limit number of accounts that a transaction can lock (backport #22201) (#22263)
* Limit number of accounts that a transaction can lock (#22201)

(cherry picked from commit 2b5e00d36d)

# Conflicts:
#	accountsdb-plugin-postgres/src/postgres_client/postgres_client_transaction.rs
#	runtime/src/accounts.rs
#	runtime/src/bank.rs
#	sdk/src/feature_set.rs
#	sdk/src/transaction/error.rs
#	storage-proto/proto/transaction_by_addr.proto
#	storage-proto/src/convert.rs

* resolve conflicts

Co-authored-by: Justin Starry <justin@solana.com>
2022-01-04 11:34:34 +00:00
mergify[bot]
7d2589e2ac Documentation typos (#22262) (#22268)
* Fix typo markdown link

* Add missing punctuation full stop

(cherry picked from commit 9665da9d0b)

Co-authored-by: glihm <dev@glihm.net>
2022-01-04 11:15:06 +00:00
mergify[bot]
77558c315d Fixed issue #22124 -- missing historical data if slot updated later. (#22193) (#22259)
* Fixed issue #22124 -- missing historical data if slot updated later.

* Fixed a couple of comments

(cherry picked from commit 5b6027bef0)

Co-authored-by: Lijun Wang <83639177+lijunwangs@users.noreply.github.com>
2022-01-04 07:18:58 +00:00
mergify[bot]
464d533da3 Flip iter operations to keep associated address/header/packets together (#22245) (#22257)
Flip iter operations to keep associated address/header/packets together

Before this change, if cast_socket_addr() returned a None for any
address/header pair, the subsequent zip() would misalign the
address/header pair and packet. So, this change zips all three together,
then does filter_map() so keep things aligned.

Additionally, compute total_size inline to avoid running through packets
a second time.

(cherry picked from commit 20b61e28b6)

Co-authored-by: steviez <steven@solana.com>
2022-01-04 07:06:06 +00:00
mergify[bot]
f8bf478fde Fix bug, add error specific timings (#22225) (#22252)
(cherry picked from commit 005592998d)

Co-authored-by: carllin <carl@solana.com>
2022-01-04 02:53:59 +00:00
mergify[bot]
35fb47d1ce removes epoch_authorized_voters from VoteTracker (backport #22192) (#22248)
* removes epoch_authorized_voters from VoteTracker (#22192)

https://github.com/solana-labs/solana/pull/22169
verifies authorized-voter early on in vote-listener pipeline; and so
VoteTracker no longer needs to maintain and check for epoch authorized
voters.

(cherry picked from commit 69d71f8f86)

# Conflicts:
#	core/src/cluster_info_vote_listener.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2022-01-04 01:51:24 +00:00
Michael Vines
5bd27dd175 Correctly set CI_COMMIT when Buildkite provides HEAD instead of a real commit 2022-01-03 17:39:49 -08:00
Michael Vines
794f28d9ab Switch from arm64-apple-darwin to aarch64-apple-darwin to align with Rust's target names 2022-01-03 17:16:49 -08:00
Michael Vines
d7a673f7f5 Add support for arm64-apple-darwin release/channel artifacts 2022-01-03 17:16:34 -08:00
Michael Vines
b3fa1288aa Use experimential docker virtualization framework for arm64
(cherry picked from commit ed0b47c6f8)
2022-01-03 16:54:37 -08:00
mergify[bot]
3e4e2e9113 Prevent lookup tables from being closed during deactivation slot (#22221) (#22247)
(cherry picked from commit bbe5b66324)

Co-authored-by: Justin Starry <justin@solana.com>
2022-01-03 23:32:03 +00:00
Michael Vines
fd4754e5a9 Correctly set CI_OS_NAME for macOs buildkite agents 2022-01-03 12:54:57 -08:00
mergify[bot]
0a9460ed8b re-calibrate limit based on mainnet data (backport #21995) (#22212)
* re-calibrate limit based on mainnet data, see issue #21917

(cherry picked from commit d743c2917c)

# Conflicts:
#	runtime/src/block_cost_limits.rs

* set secp256k1 cost similar to sigverify

(cherry picked from commit a2a7e91ad6)

* removes backport merge conflicts

Co-authored-by: Tao Zhu <tao@solana.com>
2022-01-03 19:22:10 +00:00
mergify[bot]
478c641cb5 Fix token-balance owner type in docs (#22240) (#22242)
(cherry picked from commit 9029b46570)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2022-01-03 18:28:54 +00:00
mergify[bot]
735f000952 Remove Xargo.toml reference (#22239)
(cherry picked from commit 56fd32bda2)

Co-authored-by: Michael Vines <mvines@gmail.com>
2022-01-03 17:39:19 +00:00
Alexander Meißner
264bb903a3 Bump rbpf to v0.2.21 (#22216) (#22217)
(cherry picked from commit 9139be89b7)
2022-01-01 20:42:53 +00:00
mergify[bot]
7c5d3e5874 Exit early on BigTable error (#22200) (#22209)
(cherry picked from commit 0b1b36f088)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2022-01-01 00:45:18 +00:00
mergify[bot]
70d5b6aeaf Bump solana_rbpf to version v0.2.20 (#22164) (#22207)
(cherry picked from commit 8a43e2d889)

Co-authored-by: Alexander Meißner <AlexanderMeissner@gmx.net>
2021-12-31 21:57:20 +00:00
mergify[bot]
ca451ea23e checks for authorized voter early on in the vote-listener pipeline (backport #22169) (#22206)
* checks for authorized voter early on in the vote-listener pipeline (#22169)

Before votes are verified that they are signed by the authorized voter,
they might be dropped in verified-vote-packets code. If there are
enough many spam votes from unauthorized voters, this may potentially
drop valid votes but keep the false ones.
https://github.com/solana-labs/solana/blob/57986f982/core/src/verified_vote_packets.rs#L165-L168

(cherry picked from commit c0c6038654)

# Conflicts:
#	core/src/cluster_info_vote_listener.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-12-31 21:46:12 +00:00
mergify[bot]
113d261a2c Count compute units even when transaction errors (backport #22182) (#22199)
* Count compute units even when transaction errors (#22182)

(cherry picked from commit d06e6c7425)

# Conflicts:
#	program-runtime/src/invoke_context.rs
#	runtime/src/cost_model.rs
#	runtime/src/message_processor.rs

* Resolve conflicts

Co-authored-by: carllin <carl@solana.com>
2021-12-31 21:14:00 +00:00
mergify[bot]
c6ab915668 chore: update transaction error links in docs (#22189) (#22197)
(cherry picked from commit 4e4577afbe)

Co-authored-by: Jacob Creech <82475023+jacobcreech@users.noreply.github.com>
2021-12-30 22:32:10 +00:00
Pierre
d5c0ffc11f Update install/src/command.rs
Co-authored-by: Trent Nelson <trent.a.b.nelson@gmail.com>
(cherry picked from commit 29edb130cc)
2021-12-30 07:30:17 -08:00
Arrowana
6a2b62de62 Add connect timeout and change overall timeout to None
(cherry picked from commit 3c1416091e)
2021-12-30 07:30:17 -08:00
Arrowana
4645be3e52 fix: Installer increase download req timeout from 30 seconds to 6 minutes
(cherry picked from commit a1912f8400)
2021-12-30 07:30:17 -08:00
carllin
7efd0391e9 Revert "Count compute units even when transaction errors (backport #22059) (#22154)" (#22175)
This reverts commit 401c542d2a.
2021-12-30 02:39:25 -05:00
mergify[bot]
6a556c5adb Stream additional block metadata via plugin (#22023) (#22179)
* Stream additional block metadata through plugin
blockhash, block_height, block_time, rewards are streamed

(cherry picked from commit f14928a970)

Co-authored-by: Lijun Wang <83639177+lijunwangs@users.noreply.github.com>
2021-12-30 05:44:12 +00:00
mergify[bot]
0cd45400ca Add docs for notifying transactions via plugin (#22097) (#22178)
* Added documentations for streaming transactions via plugin

* Updated comments for transaction info

* Updated doc on transaction format

* Removed a white space

* Apply suggestions from code review from Tyera

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

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

Co-authored-by: Lijun Wang <83639177+lijunwangs@users.noreply.github.com>
2021-12-30 05:10:32 +00:00
mergify[bot]
531f36c571 Don't forward packets received from TPU forwards port (#22078) (#22171)
* Don't forward packets received from TPU forwards port

* Add banking stage test

(cherry picked from commit b1d9a2e60e)

Co-authored-by: Justin Starry <justin@solana.com>
2021-12-30 10:42:28 +08:00
mergify[bot]
9c9d3e8b6b discards serialized gossip crds votes if cannot parse tx (backport #22129) (#22172)
* discards serialized gossip crds votes if cannot parse tx (#22129)

(cherry picked from commit c9c78622a8)

# Conflicts:
#	gossip/src/crds_value.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-12-29 22:38:12 +00:00
mergify[bot]
74b98c2dd4 get_signatures_for_address does not correctly account for result sets that span local and Bigtable sources (#22115) (#22168)
* get_signatures_for_address does not correctly account for result sets that span Blockstore and Bigtable.

This causes Bigtable to return `RowNotFound` until the new tx is uploaded.

Check that `before` exists in Bigtable, and if not, set it to `None` to return the full data set.

References #21442
Closes #22110

* Differentiate between before sig not found and no newer signatures

* Dedupe bigtable results to account for potential upload race

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

Co-authored-by: Omar Kilani <omar.kilani@gmail.com>
2021-12-29 19:52:36 +00:00
mergify[bot]
9fb67f9b07 Prevent log spam (#22148) (#22152)
(cherry picked from commit f061059e45)

Co-authored-by: carllin <carl@solana.com>
2021-12-29 08:28:48 +00:00
mergify[bot]
401c542d2a Count compute units even when transaction errors (backport #22059) (#22154)
* Count compute units even when transaction errors (#22059)

(cherry picked from commit eaa8c67bde)

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

* Fix merge conflicts

Co-authored-by: carllin <carl@solana.com>
2021-12-29 08:04:12 +00:00
mergify[bot]
14ed446923 cargo-build-bpf: Add Windows support (#20276) (#22155)
* cargo-build-bpf: Add Windows support

* Update error message

(cherry picked from commit 57986f982a)

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-12-29 03:07:39 +00:00
mergify[bot]
adc584ee22 Add (preflight) simulation to BanksClient (#22084) (#22149)
* Add more-legitimate conversion from legacy Transaction to SanitizedTransaction

* Add Banks method with preflight checks

* Expose BanksClient method with preflight checks

* Unwrap simulation err

* Add Bank simulation method that works on unfrozen Banks

* Add simpler api

* Better name: BanksTransactionResultWithSimulation

(cherry picked from commit 422a095647)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-12-28 22:04:27 +00:00
mergify[bot]
810ca36eae skip reporting all-zero stats (#22054)
(cherry picked from commit 9c5d82557a)

Co-authored-by: Tao Zhu <tao@solana.com>
2021-12-28 07:03:13 +00:00
mergify[bot]
16f821ea8c Ensure AncestorHashesSerice selects an open port (#21919) (#21997)
(cherry picked from commit 7f6fb6937a)

Co-authored-by: carllin <wumu727@gmail.com>
2021-12-28 06:46:59 +00:00
mergify[bot]
584e9bfbe7 docs: fix typo (#22116) (#22118)
(cherry picked from commit f643a8b425)

Co-authored-by: Samuel Oloruntoba <git@kayandra.co>
2021-12-26 04:36:49 +00:00
mergify[bot]
3ad4c3306c Add PubsubClient::vote_subscribe (#22114)
(cherry picked from commit 0a0fc85282)

Co-authored-by: Kirill Fomichev <fanatid@ya.ru>
2021-12-25 23:19:46 +00:00
mergify[bot]
be0bcd85ed tracks erasure coding shreds' indices explicitly (#21822) (#22094)
The indices for erasure coding shreds are tied to data shreds:
https://github.com/solana-labs/solana/blob/90f41fd9b/ledger/src/shred.rs#L921

However with the upcoming changes to erasure schema, there will be more
erasure coding shreds than data shreds and we can no longer infer coding
shreds indices from data shreds.

The commit adds constructs to track coding shreds indices explicitly.

(cherry picked from commit 65d59f4ef0)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-12-23 19:38:50 +00:00
Ryan Laursen
8708186760 Update checks.rs
(cherry picked from commit d06c04d02c)
2021-12-23 07:00:26 -08:00
Ryan Laursen
8f3e37c174 Remove msg spam from deploying
(cherry picked from commit 52c1eb0160)
2021-12-23 07:00:26 -08:00
mergify[bot]
7d61935bf1 Bump bpf-tools to v1.21 (#22083)
(cherry picked from commit 7cc6262b5a)

Co-authored-by: Dmitri Makarov <dmakarov@alumni.stanford.edu>
2021-12-23 03:38:04 +00:00
mergify[bot]
a70eb098f4 Fix transaction pk violation (#22057) (#22076)
* Handle PK violation issue for transaction notification. The transaction might be replayed due to
validator restart.

(cherry picked from commit d6de4a2f4e)

Co-authored-by: Lijun Wang <83639177+lijunwangs@users.noreply.github.com>
2021-12-23 00:33:35 +00:00
mergify[bot]
f31593bfbe Update jsonrpc-api.md to document 'owner' property (#22074) (#22077)
* Update jsonrpc-api.md to document 'owner' property

Documents 'owner' property on the token balances struct.

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

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

Co-authored-by: splintred <91386295+splintred@users.noreply.github.com>
2021-12-23 00:13:30 +00:00
mergify[bot]
8f26c71964 Fixed a typo in the SQL statement (#21872) (#22075)
* Fixed a typo in the SQL statement

* Fixed additional two errors in the postgres database objects

(cherry picked from commit b610e5503e)

Co-authored-by: Lijun Wang <83639177+lijunwangs@users.noreply.github.com>
2021-12-22 22:55:58 +00:00
mergify[bot]
9fbaaa5102 Increment execution timings on errors as well (#22053) (#22072)
(cherry picked from commit 37f6777ceb)

Co-authored-by: carllin <carl@solana.com>
2021-12-22 22:50:19 +00:00
Will Hickey
78e7913352 Bump version to 1.9.3 (#22065) 2021-12-22 11:41:03 -06:00
Tyera Eulberg
f58b87befe v1.9: bump tarpc from 0.26.2 to 0.27.2 and add BanksClientError (#22055)
* chore: bump tarpc from 0.26.2 to 0.27.2

Bumps [tarpc](https://github.com/google/tarpc) from 0.26.2 to 0.27.2.
- [Release notes](https://github.com/google/tarpc/releases)
- [Changelog](https://github.com/google/tarpc/blob/master/RELEASES.md)
- [Commits](https://github.com/google/tarpc/commits)

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

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

* [auto-commit] Update all Cargo lock files

* Accommodate breaking changes

* Reword incorrect error message

* Add error module

* Revert client Error type to io::Error; easy transition to BanksClientError

* Bump tracing crates in programs

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: dependabot-buildkite <dependabot-buildkite@noreply.solana.com>
2021-12-22 03:41:16 +00:00
mergify[bot]
1a2823b875 chore: bump lru from 0.7.0 to 0.7.1 (#22018) (#22056)
Bumps [lru](https://github.com/jeromefroe/lru-rs) from 0.7.0 to 0.7.1.
- [Release notes](https://github.com/jeromefroe/lru-rs/releases)
- [Changelog](https://github.com/jeromefroe/lru-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jeromefroe/lru-rs/compare/0.7.0...0.7.1)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
(cherry picked from commit 69d0b08dd8)

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-21 16:27:43 -07:00
mergify[bot]
75fe0d3ecf Fix #21986 (#22035) (#22049)
* Partial revert "Updates documentation around what needs to be passed in CPI. (#21633)"

* Enforces the program_id being passed explicitly by removing it from get_instruction_keyed_accounts().

* instruction_accounts => instructions_account

(cherry picked from commit ba8e15848e)

Co-authored-by: Alexander Meißner <AlexanderMeissner@gmx.net>
2021-12-21 17:54:18 +00:00
mergify[bot]
c296a6c9ed The sidebar for the plugin doc is showing the item as "Overview", corrected the styles (#22033) (#22040)
(cherry picked from commit 2347f65133)

Co-authored-by: Lijun Wang <83639177+lijunwangs@users.noreply.github.com>
2021-12-21 02:58:53 +00:00
mergify[bot]
57e5406476 Add deactivation cooldown before address lookup tables can be closed (#22011) (#22036)
(cherry picked from commit f5d1115468)

Co-authored-by: Justin Starry <justin@solana.com>
2021-12-21 02:10:14 +00:00
mergify[bot]
4f57c4a4fe Fix weird formatting of bullets (#22013) (#22030)
(cherry picked from commit 116517fb6d)

Co-authored-by: Kardashev <96332127+0xkardashev@users.noreply.github.com>
2021-12-20 20:41:18 +00:00
mergify[bot]
c4b3b2865d Update program close docs (#22026) (#22027)
(cherry picked from commit b8eff3456c)

Co-authored-by: Jack May <jack@solana.com>
2021-12-20 18:55:39 +00:00
mergify[bot]
f58c375b1f typo: lanaguage -> language (#22009) (#22015)
(cherry picked from commit e92a81b741)

Co-authored-by: Peter Johnson <peter@geocode.earth>
2021-12-20 07:34:31 +00:00
mergify[bot]
bf41c53f11 chore: add blockSubscribe api docs (#22002) (#22008)
Co-authored-by: Zano <segfaultdoctor@protonmail.com>
(cherry picked from commit df6a4930b9)

Co-authored-by: segfaultdoctor <seg@jito.network>
2021-12-19 16:48:36 +00:00
mergify[bot]
e3a4b98432 removes Select in favor of recv_timeout/try_iter (#21981) (#22001)
crossbeam_channel::Select::ready_timeout might return with success spuriously.

(cherry picked from commit 7476dfeec0)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-12-18 19:37:07 +00:00
mergify[bot]
91657ba8fe new net-stats require a new table (#21996) (#22000)
(cherry picked from commit 3fe942ab30)

Co-authored-by: Jeff Biseda <jbiseda@gmail.com>
2021-12-18 10:26:16 +00:00
mergify[bot]
35ee48bec9 RPC Block Subscription (backport #21787) (#21992)
* RPC Block Subscription (#21787)

* add stuff

* compiling

* add notify block

* wip

* feat: add blockSubscribe pubsub method

* address PR comments

Co-authored-by: Lucas B <buffalu@jito.network>
Co-authored-by: Zano <segfaultdoctor@protonmail.com>
(cherry picked from commit 76098dd42a)

# Conflicts:
#	Cargo.lock
#	client-test/Cargo.toml
#	rpc/src/rpc_subscriptions.rs

* Fix conflicts

Co-authored-by: segfaultdoctor <seg@jito.network>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-12-18 01:43:37 +00:00
mergify[bot]
02cfa85214 Update to reed-solomon-erasure 5.0.1, to get simd-accel on M1 macs (#21990)
(cherry picked from commit 5f054cd51b)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-12-18 00:52:21 +00:00
mergify[bot]
02be3a6568 Check file size of snapshot_version when unarchiving snapshot (#21925) (#21983)
(cherry picked from commit 0f6e8d3385)

Co-authored-by: mooori <moritz.zielke@gmail.com>
2021-12-17 21:02:53 +00:00
mergify[bot]
b20fae5a09 simplifies ShredIndex api (#21932) (#21959)
(cherry picked from commit efd64a3862)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-12-17 19:50:49 +00:00
mergify[bot]
e572678176 removes next_shred_index from return value of entries to shreds api (#21961) (#21980)
next-shred-index is already readily available from returned data shreds.
The commit simplifies the api for upcoming changes to erasure coding
schema which will require explicit tracking of indices for coding shreds
as well as data shreds.

(cherry picked from commit 89d66c3210)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-12-17 17:57:57 +00:00
mergify[bot]
f4521002b9 Clean up demote program write lock feature (backport #21949) (#21969)
* Clean up demote program write lock feature (#21949)

* Clean up demote program write lock feature

* fix test

(cherry picked from commit 6ff0be6a82)

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

* resolve conflicts

Co-authored-by: Justin Starry <justin@solana.com>
2021-12-17 04:45:22 +00:00
mergify[bot]
0c5a2bcd5a Update getSignaturesForAddress and getConfirmedSignaturesForAddress2 RPC call description (#21955) (#21960)
* Update jsonrpc-api.md

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

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

* Wrap 80chars

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

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

Co-authored-by: jdcaballerov <743513+jdcaballerov@users.noreply.github.com>
2021-12-16 20:59:51 +00:00
mergify[bot]
c25d16bf0d adds ErasureSetId identifying erasure coding sets of shreds (backport #21928) (#21946)
* adds ErasureSetId identifying erasure coding sets of shreds (#21928)

(cherry picked from commit 8183f28636)

# Conflicts:
#	ledger/src/blockstore.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-12-16 17:49:39 +00:00
mergify[bot]
301e38044a Fixes the calculation of the "compute_meter_consumption" across process_instruction() and process_message(). (#21944) (#21945)
(cherry picked from commit 49cb161203)

Co-authored-by: Alexander Meißner <AlexanderMeissner@gmx.net>
2021-12-16 16:28:28 +00:00
Michael Vines
bfa6302985 Bump version to 1.9.2 2021-12-15 16:18:14 -08:00
Kirill Fomichev
b66e2ae353 add caching_enabled option to test-validator
(cherry picked from commit 5fb7da12f2)
2021-12-15 16:11:51 -08:00
Michael Vines
3967dc8685 rebase 2021-12-15 15:33:45 -08:00
Michael Vines
569c83295d Update argument name
(cherry picked from commit ed924e3bc4)
2021-12-15 15:33:45 -08:00
losman0s
a462c58594 Add option to load accounts from file
This introduces the `--clone-from-file` option for
solana-test-validator. It allows specifying any number of files
(without extension) containing account info and data, which will be
loaded at genesis. This is similar to `--bpf-program` for programs
loading.

The files will be searched for in the CWD or in `tests/fixtures`.

Example: `solana-test-validator --clone-from-file SRM_token USD_token`
(cherry picked from commit 9b06d64eb8)

# Conflicts:
#	test-validator/Cargo.toml
2021-12-15 15:33:45 -08:00
losman0s
7dba8bb49f Add complete account dump to file
This commit introduces the ability to dump the complete content of an
account to a JSON file (compact or not depending on the provided format
option).

Example:

```sh
solana account -u m \
  --output json-compact \
  --output-file SRM_token.json \
  SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt
```

Note: Behavior remains untouched if format option `--output` is not
provided (only account data gets written to file).

(cherry picked from commit 0e9e67b65d)
2021-12-15 15:33:45 -08:00
mergify[bot]
c907d4444d add accountsdb-plugin-config to test-validator (#21918)
(cherry picked from commit c2a94a8fb0)

Co-authored-by: Kirill Fomichev <fanatid@ya.ru>
2021-12-15 09:48:12 +00:00
Michael Vines
b4c847557b Restore solana_validator::test_validator export
(cherry picked from commit e124659aca)
2021-12-15 00:29:04 -08:00
mergify[bot]
de48347078 Add json support for feature sets; also print output after feature list (#21905) (#21914)
* Add json support for feature sets; also print output after feature list

* Move stringifying into Display implementation

(cherry picked from commit dcd2854829)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-12-15 07:08:39 +00:00
Michael Vines
9f173d3717 Add helper crate to generate syscalls.txt 2021-12-14 21:34:36 -08:00
Michael Vines
dcd76e484f Update openssl-src package to resolve cargo audit complaint
(cherry picked from commit 7ba27e5cae)
2021-12-14 19:09:26 -08:00
mergify[bot]
2246135654 Document solana_program::instruction (#21817) (#21906)
* Document solana_program::instruction

* 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 dcb5849484)

Co-authored-by: Brian Anderson <andersrb@gmail.com>
2021-12-15 00:55:56 +00:00
mergify[bot]
41ea597256 Fix subtraction overflow (#21871) (#21901)
(cherry picked from commit cb395abff7)

Co-authored-by: carllin <carl@solana.com>
2021-12-14 23:22:47 +00:00
Michael Vines
fb955bd4ec Update Cargo.toml 2021-12-14 14:18:20 -08:00
Michael Vines
5c3fbb384f Futures 0.3.18 has been yanked, back off to .17
(cherry picked from commit 2a6dcb2ffd)

# Conflicts:
#	ledger/Cargo.toml
2021-12-14 14:18:20 -08:00
mergify[bot]
a056fd88cb uses Option<Slot> for SlotMeta.parent_slot (backport #21808) (#21899)
* uses Option<Slot> for SlotMeta.parent_slot (#21808)

SlotMeta.parent_slot for the head of a detached chain of slots is
unknown and that is indicated by u64::MAX which lacks type-safety:
https://github.com/solana-labs/solana/blob/6c108c8fc/ledger/src/blockstore_meta.rs#L203-L205

The commit changes the type to Option<Slot>. Backward compatibility is
maintained by customizing serde serialize/deserialize implementations.

(cherry picked from commit 8d980f07ba)

# Conflicts:
#	ledger-tool/src/main.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-12-14 21:42:57 +00:00
mergify[bot]
2f1816d1db adds ShredId uniquely identifying each shred (backport #21820) (#21897)
* adds ShredId uniquely identifying each shred (#21820)

(cherry picked from commit 4ceb2689f5)

# Conflicts:
#	ledger/src/blockstore.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-12-14 21:03:08 +00:00
mergify[bot]
2cd2f3ba7b Bump rbpf to v0.2.19 (#21880) (#21891)
* Bump rbpf to v0.2.19

Co-authored-by: Alexander Meißner <AlexanderMeissner@gmx.net>
(cherry picked from commit 509bcd2e74)

Co-authored-by: Jack May <jack@solana.com>
2021-12-14 20:30:31 +00:00
Michael Vines
135dfdbf1e Don't publish rbpf-cli to crates.io 2021-12-14 12:12:19 -08:00
Michael Vines
fad4bfdf2a Don't publish poh-bench to crates.io 2021-12-14 12:10:03 -08:00
mergify[bot]
a9d4728c35 Deserialize accounts before acquiring stakes cache lock (#21733) (#21889)
* Deserialize stored accounts before locking stakes cache

* fix test

(cherry picked from commit 2bbe1d875a)

Co-authored-by: Justin Starry <justin@solana.com>
2021-12-14 16:47:01 +00:00
mergify[bot]
3977bcde63 Add missing word "that" (#21878) (#21884)
(cherry picked from commit 746869fdac)

Co-authored-by: Raza <42661870+AlmostEfficient@users.noreply.github.com>
2021-12-14 14:44:48 +00:00
mergify[bot]
cf2a9de19c Add solana-cli-config link to rust-api.md (#21840) (#21874)
(cherry picked from commit 033106ed81)

Co-authored-by: Brian Anderson <andersrb@gmail.com>
2021-12-14 08:22:13 +00:00
mergify[bot]
5e2b12aee5 Restore ALL behavior; add enum variant, comments, and help text to make behavior clearer (#21854) (#21863)
(cherry picked from commit bed1b143a5)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-12-14 05:21:25 +00:00
mergify[bot]
6c329e2fd3 Fixup RPC docs (backport #21858) (#21864)
* Remove old notes referring to EOL versions

(cherry picked from commit eebaf89874)

* Add notes about new v1.9 rpc apis

(cherry picked from commit fd212fd2a4)

Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-12-14 02:46:44 +00:00
mergify[bot]
0376045c7d cli: Order displayed feature list by status (#21810) (#21830)
(cherry picked from commit 1149c1880d)

Co-authored-by: Justin Starry <justin@solana.com>
2021-12-13 14:39:47 +00:00
Michael Vines
c1f54c22ed Remove the 5 integer msg! form
(cherry picked from commit c5c699a918)
2021-12-11 12:47:43 -08:00
Lijun Wang
0576d133ad Add Accountsdb plugin documentations (#21746) (#21799)
Add the public facing documentation about the plugin framework: explaining the interface, how to load plugin and the example PostgreSQL plugin implementation.
Updated the rust documentation for the plugin interfaces for accounts and slot.
This changes are targeted for v1.8. Information about transactions will be updated later.
2021-12-11 11:04:22 -08:00
mergify[bot]
9956afb2bd uses Option<u64> for SlotMeta.last_index (#21775) (#21806)
SlotMeta.last_index may be unknown and current code is using u64::MAX to
indicate that:
https://github.com/solana-labs/solana/blob/6c108c8fc/ledger/src/blockstore_meta.rs#L169-L174

This lacks type-safety and can introduce bugs if not always checked for
Several instances of slot_meta.last_index + 1 are also subject to
overflow.

This commit updates the type to Option<u64>. Backward compatibility is
maintained by customizing serde serialize/deserialize implementations.

(cherry picked from commit e08139f949)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-12-11 17:39:05 +00:00
mergify[bot]
01941cf3de Rename Packets to PacketBatch (backport #21794) (#21805)
* Rename Packets to PacketBatch (#21794)

(cherry picked from commit 254ef3e7b6)

# Conflicts:
#	core/src/verified_vote_packets.rs

* resolve conflicts

Co-authored-by: Justin Starry <justin@solana.com>
2021-12-11 16:53:23 +00:00
Tao Zhu
4b63d51e3e Bump version to 1.9.1 (#21802) 2021-12-11 12:50:36 +00:00
mergify[bot]
5bf4445ae6 Add address lookup table program (backport #21616) (#21789)
* Add address lookup table program (#21616)

* Add address lookup table program

* feedback

(cherry picked from commit 9b41ddd9ba)

# Conflicts:
#	runtime/Cargo.toml

* resolve conflicts

Co-authored-by: Justin Starry <justin@solana.com>
2021-12-11 05:26:46 +00:00
Justin Starry
7782d34bbf Add StakesCache struct to abstract away locking (#21738) (#21796) 2021-12-10 22:38:04 -05:00
mergify[bot]
2c4765e75a Bump solana_rbpf to version v0.2.18 (#21774) (#21786)
(cherry picked from commit a5a0dabe7b)

Co-authored-by: Alexander Meißner <AlexanderMeissner@gmx.net>
2021-12-11 02:38:03 +00:00
mergify[bot]
e71ea19e60 adds back ErasureMeta::first_coding_index field (#21623) (#21785)
https://github.com/solana-labs/solana/pull/16646
removed first_coding_index since the field is currently redundant and
always equal to fec_set_index.
However, with upcoming changes to erasure coding schema, this will no
longer be the same as fec_set_index and so requires a separate field to
represent.

(cherry picked from commit 49ba09b333)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-12-10 23:14:10 +00:00
mergify[bot]
ed0040d555 Update to Rust 1.57.0 (#21779)
(cherry picked from commit 15a9fa6f53)

Co-authored-by: Steven Czabaniuk <steven@solana.com>
2021-12-10 22:23:48 +00:00
mergify[bot]
da9e6826ac Move type alias and use it more broadly (#21763) (#21777)
(cherry picked from commit 350845c513)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-12-10 21:44:41 +00:00
mergify[bot]
68fc72a7f4 Add more reporting for invalid stake cache members and prune them (#21654) (#21741)
* Add more reporting for invalid stake cache members

* feedback

(cherry picked from commit 6fc329180b)

Co-authored-by: Justin Starry <justin@solana.com>
2021-12-10 18:30:16 +00:00
mergify[bot]
2a6bb2b954 Migrate from address maps to address lookup tables (#21634) (#21773)
* Migrate from address maps to address lookup tables

* update sanitize error

* cargo fmt

* update abi

(cherry picked from commit 6c108c8fc3)

Co-authored-by: Justin Starry <justin@solana.com>
2021-12-10 18:10:37 +00:00
mergify[bot]
ef51778c78 Nits in message-processor (#21755) (#21762)
* Fixup typo

* Simplify types slightly

(cherry picked from commit c1386d66e6)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-12-10 11:24:20 -05:00
mergify[bot]
abecf292a3 Expand docs for Pubkey::create_program_address (#21750) (#21759)
* Expand docs for Pubkey::create_program_address

* Update sdk/program/src/pubkey.rs

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

Co-authored-by: Brian Anderson <andersrb@gmail.com>
2021-12-10 11:23:54 -05:00
Michael Vines
a31660815f rebase 2021-12-09 18:41:47 -08:00
Michael Vines
539ad4bea6 Remove libcurl to prevent wasm-pack segfault in libssl
(cherry picked from commit f32216588d)
2021-12-09 18:41:47 -08:00
Michael Vines
85f601993f Cargo.lock
(cherry picked from commit f4babb7566)

# Conflicts:
#	Cargo.lock
#	programs/bpf/Cargo.lock
2021-12-09 18:41:47 -08:00
Michael Vines
b0754cc575 Add initial wasm bindings for Instruction, SystemProgram and Transaction
(cherry picked from commit a35df1cb02)
2021-12-09 18:41:47 -08:00
Michael Vines
effd0b2547 Add wasm bindings for Hash
(cherry picked from commit 03a956e8d9)
2021-12-09 18:41:47 -08:00
Michael Vines
8836069719 Add wasm bindings for Pubkey and Keypair
(cherry picked from commit 488dc37fec)
2021-12-09 18:41:47 -08:00
mergify[bot]
2698a5c705 AcctIdx: env var to enable testing of disk buckets (#21494) (#21723)
(cherry picked from commit 54862eba0d)

Co-authored-by: Jeff Washington (jwash) <wash678@gmail.com>
2021-12-09 23:39:06 +00:00
mergify[bot]
dd157fd47f Fixed minor issues with the cluster overview docs which had confused some (#21744) (#21745)
new users.

(cherry picked from commit 6d18b6bab5)

Co-authored-by: bji <bryan@ischo.com>
2021-12-09 20:41:21 +00:00
mergify[bot]
8cacf82cb8 adds more sanity checks to shreds (#21675) (#21734)
(cherry picked from commit 8063273d09)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-12-09 18:44:43 +00:00
mergify[bot]
8ee5fbc5c0 simulateTransaction now returns the correct error code if accounts are provided as input (#21716)
(cherry picked from commit 824994db69)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-12-09 01:12:42 +00:00
mergify[bot]
f2a6b94e5c SDK: Add stdlib.h include to pull in abort() (#21700) (#21705)
(cherry picked from commit 923720f529)

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-12-08 17:31:11 +00:00
mergify[bot]
ef970bb14a - Implicitly fixes invoke_context.return_data not being reset between instructions in process_message. (#21671) (#21684)
- Lets InvokeContext::process_cross_program_instruction() handle the first invocation depth too.
- Marks InvokeContext::verify(), InvokeContext::verify_and_update() and InvokeContext::process_executable_chain() private.
- Renames InvokeContext::process_cross_program_instruction() to InvokeContext::process_instruction().
- Removes InvokeContext::new_mock_with_sysvars().

(cherry picked from commit 1df88837c8)

Co-authored-by: Alexander Meißner <AlexanderMeissner@gmx.net>
2021-12-08 10:48:49 +00:00
Jarred Nicholls
cabd851904 Avoid entropy sources when constructing a solana_program::message::Message.
The solana-program crate can be used in certain embedded environments (HSMs) where
the source of entropy, whether used for cryptographic purposes or not, is tightly
controlled. In these cases, using the default OS source of entrophy is not always
acceptable. Thus, using the default Rust stdlib entropy source for seeding its
default hasher, is prohibited. This means any use of HashMap/HashSet must be able
to be constructed and used with a custom hasher implementation.

This commit removes the use of Itertools::unique() to dedupe Instructions that are
being compiled into a new Message, which uses a default-configured HashMap
under-the-hood. Instead, we use a BTreeSet which does not invoke any entropy
source in order to seed a hash implementation.

(cherry picked from commit 4da435f2a0)
2021-12-07 22:36:21 -08:00
mergify[bot]
2d2ef59550 Ensure we have keys to activate these features (#21669) (#21674)
(cherry picked from commit 45e56c599d)

Co-authored-by: Sean Young <sean@mess.org>
2021-12-07 23:24:11 +00:00
mergify[bot]
b7b56d5016 Docs: Solflare web/app updates (#21540) (#21668)
* Update Solflare description

* Add Solflare to mobile wallets

* Sort mobile wallets alphabetically

* Sort web wollets alphabetically

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

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

* Update docs/src/wallet-guide/web-wallets.md

* Update docs/src/wallet-guide/web-wallets.md

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

Co-authored-by: Justin Starry <justin.m.starry@gmail.com>
(cherry picked from commit a2477c1f32)

Co-authored-by: Boris Vujicic <turshija@gmail.com>
2021-12-07 16:44:28 +00:00
mergify[bot]
18e3a635b4 docs: Fix SOL staked formula (#21615) (#21667)
Fix the formula on the proposal page: https://docs.solana.com/implemented-proposals/ed_overview/ed_validation_client_economics/ed_vce_state_validation_protocol_based_rewards

(cherry picked from commit b57097ef18)

Co-authored-by: Melroy van den Berg <melroy@melroy.org>
2021-12-07 16:01:12 +00:00
mergify[bot]
2b4347d502 Add option to reclaim accounts-cluster-bench accounts/lamports (backport #21656) (#21658)
* Add option to reclaim accounts-cluster-bench accounts/lamports (#21656)

* Add option to reclaim accounts-cluster-bench accounts/lamports

* lint

(cherry picked from commit 205fd95722)

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

* Fix conflict

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-12-07 09:18:48 +00:00
mergify[bot]
87accd16d8 Fixup flaky tests (#21617) (#21647)
* Fixup flaky tests

* Fixup listeners

(cherry picked from commit f493a88258)

Co-authored-by: carllin <carl@solana.com>
2021-12-07 03:54:14 +00:00
mergify[bot]
0e969015fc Add offline and fee-payer utilities to CLI vote module (#21579) (#21649)
* create-vote-account: add offline, nonce, fee_payer capabilities

* vote-authorize: add offline, nonce, fee-payer

* vote-update-things: add offline, nonce, fee-payer

* withdraw-vote: add offline, nonce, fee-payer

* close-vote-acct: add fee-payer

* Allow WithdrawVoteAccount to empty account, since offline operations cannot perform account state queries as in CloseVoteAccount

* Fix lint

* Update offline-signing docs

* Add some parse unit tests

* Add offline integration test

(cherry picked from commit 873fe81bc0)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-12-07 01:51:02 +00:00
mergify[bot]
46935c022e Ensure that StakeDelegations and StakeHistory serde (#21640) (#21653)
Add tests to StakeDelegations and StakeHistory to ensure that the outer
types serialize and deserialize correctly to/from the inner types.

(cherry picked from commit da4015a959)

Co-authored-by: Brooks Prumo <brooks@solana.com>
2021-12-07 01:44:49 +00:00
mergify[bot]
8a7106bc08 Remove activated feature for filtering invalid stakes from rewards (#21641) (#21651)
(cherry picked from commit a1adcb23b6)

Co-authored-by: Justin Starry <justin@solana.com>
2021-12-07 00:58:31 +00:00
mergify[bot]
89d2f34a03 Reject vote withdraws that create non-rent-exempt accounts (backport #21639) (#21645)
* Reject vote withdraws that create non-rent-exempt accounts (#21639)

* Reject vote withdraws that create non-rent-exempt accounts

* fix mocked instruction test

(cherry picked from commit e123883b26)

# Conflicts:
#	sdk/src/feature_set.rs

* resolve conflicts

Co-authored-by: Justin Starry <justin@solana.com>
2021-12-07 00:42:01 +00:00
mergify[bot]
b3fa1e4550 Move transaction error code into new module (#21635) (#21638)
(cherry picked from commit 3dab1e711d)

Co-authored-by: Justin Starry <justin@solana.com>
2021-12-06 20:11:20 +00:00
mergify[bot]
58c755e1d4 Rework docs for Pubkey::find_program_address and friends (#21528) (#21637)
* Rework docs for Pubkey::find_program_address and friends

* Remove circular dependency

* Minor tweaks

* Apply suggestions from code review

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

* Sort solana-program dev-dependencies

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

Co-authored-by: Brian Anderson <andersrb@gmail.com>
2021-12-06 19:04:35 +00:00
mergify[bot]
60085305b4 Fix spelling of 'Borsh' (#21624)
(cherry picked from commit f3c2803af9)

Co-authored-by: Brian Anderson <andersrb@gmail.com>
2021-12-06 05:31:28 +00:00
mergify[bot]
b4c8e095bd adds back position field to coding-shred-header (#21600) (#21620)
https://github.com/solana-labs/solana/pull/17004
removed position field from coding-shred-header because as it stands the
field is redundant and unused.
However, with the upcoming changes to erasure coding schema this field
will no longer be redundant and needs to be populated.

(cherry picked from commit cd17f63d81)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-12-05 16:40:22 +00:00
mergify[bot]
3e28ffa884 Bump RpcClient node versions (#21612) (#21613)
* Bump blockhash/fee api check versions

* Bump snapshot api check version

(cherry picked from commit 3e5a5a834f)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-12-05 01:08:22 +00:00
892 changed files with 53604 additions and 108225 deletions

View File

@@ -1,19 +0,0 @@
#!/usr/bin/env bash
#
# This script is used to upload the full buildkite pipeline. The steps defined
# in the buildkite UI should simply be:
#
# steps:
# - command: ".buildkite/pipeline-upload.sh"
#
set -e
cd "$(dirname "$0")"/..
source ci/_
sudo chmod 0777 ci/buildkite-pipeline-in-disk.sh
_ ci/buildkite-pipeline-in-disk.sh pipeline.yml
echo +++ pipeline
cat pipeline.yml
_ buildkite-agent pipeline upload pipeline.yml

View File

@@ -12,14 +12,7 @@ export PS4="++"
# Restore target/ from the previous CI build on this machine
#
eval "$(ci/channel-info.sh)"
eval "$(ci/sbf-tools-info.sh)"
source "ci/rust-version.sh"
HOST_RUST_VERSION="$rust_stable"
pattern='^[0-9]+\.[0-9]+\.[0-9]+$'
if [[ ${HOST_RUST_VERSION} =~ ${pattern} ]]; then
HOST_RUST_VERSION="${rust_stable%.*}"
fi
export CARGO_TARGET_CACHE=$HOME/cargo-target-cache/"$CHANNEL"-"$BUILDKITE_LABEL"-"$SBF_TOOLS_VERSION"-"$HOST_RUST_VERSION"
export CARGO_TARGET_CACHE=$HOME/cargo-target-cache/"$CHANNEL"-"$BUILDKITE_LABEL"
(
set -x
MAX_CACHE_SIZE=18 # gigabytes

6
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,6 @@
#### Problem
#### Proposed Solution

View File

@@ -1,12 +0,0 @@
---
name: General Issue
about: Create a report describing a problem and a proposed solution
title: ''
assignees: ''
---
#### Problem
#### Proposed Solution

View File

@@ -1,70 +0,0 @@
name: Feature Gate Tracker
description: Track the development and status of an on-chain feature
title: "Feature Gate: "
labels: ["feature-gate"]
body:
- type: markdown
attributes:
value: >
Steps to add a new feature are outlined below. Note that these steps only cover
the process of getting a feature into the core Solana code.
- For features that are unambiguously good (ie bug fixes), these steps are sufficient.
- For features that should go up for community vote (ie fee structure changes), more
information on the additional steps to follow can be found at:
<https://spl.solana.com/feature-proposal#feature-proposal-life-cycle>
1. Generate a new keypair with `solana-keygen new --outfile feature.json --no-passphrase`
- Keypairs should be held by core contributors only. If you're a non-core contirbutor going
through these steps, the PR process will facilitate a keypair holder being picked. That
person will generate the keypair, provide pubkey for PR, and ultimately enable the feature.
2. Add a public module for the feature, specifying keypair pubkey as the id with
`solana_sdk::declare_id!()` within the module. Additionally, add an entry to `FEATURE_NAMES` map.
3. Add desired logic to check for and switch on feature availability.
- type: textarea
id: description
attributes:
label: Description
placeholder: Describe why the new feature gate is needed and any necessary conditions for its activation
validations:
required: true
- type: input
id: id
attributes:
label: Feature ID
description: The public key of the feature account
validations:
required: true
- type: dropdown
id: activation-method
attributes:
label: Activation Method
options:
- Single Core Contributor
- Staked Validator Vote
validations:
required: true
- type: input
id: testnet
attributes:
label: Testnet Activation Epoch
placeholder: Edit this response when feature is activated on this cluster
validations:
required: false
- type: input
id: devnet
attributes:
label: Devnet Activation Epoch
placeholder: Edit this response when feature is activated on this cluster
validations:
required: false
- type: input
id: mainnet-beta
attributes:
label: Mainnet-Beta Activation Epoch
placeholder: Edit this response when feature is activated on this cluster
validations:
required: false

View File

@@ -1,9 +1,5 @@
#### Problem
#### Summary of Changes
Fixes #
<!-- OPTIONAL: Feature Gate Issue: # -->
<!-- Don't forget to add the "feature-gate" label -->

View File

@@ -1,37 +0,0 @@
name: 'Autolock RitBot for for PR'
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
permissions:
issues: write
pull-requests: write
concurrency:
group: lock
jobs:
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v3
with:
github-token: ${{ github.token }}
pr-inactive-days: '14'
exclude-pr-created-before: ''
exclude-pr-created-after: ''
exclude-pr-created-between: ''
exclude-pr-closed-before: ''
exclude-pr-closed-after: ''
exclude-pr-closed-between: ''
include-any-pr-labels: 'automerge'
include-all-pr-labels: ''
exclude-any-pr-labels: ''
add-pr-labels: 'locked PR'
remove-pr-labels: ''
pr-comment: 'This PR has been automatically locked since there has not been any activity in past 14 days after it was merged.'
pr-lock-reason: 'resolved'
log-output: true

View File

@@ -1,38 +0,0 @@
name: 'Autolock NaviBot for closed issue'
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
permissions:
issues: write
pull-requests: write
concurrency:
group: lock
jobs:
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v3
with:
github-token: ${{ github.token }}
issue-inactive-days: '7'
exclude-issue-created-before: ''
exclude-issue-created-after: ''
exclude-issue-created-between: ''
exclude-issue-closed-before: ''
exclude-issue-closed-after: ''
exclude-issue-closed-between: ''
include-any-issue-labels: ''
include-all-issue-labels: ''
exclude-any-issue-labels: ''
add-issue-labels: 'locked issue'
remove-issue-labels: ''
issue-comment: 'This issue has been automatically locked since there has not been any activity in past 7 days after it was closed. Please open a new issue for related bugs.'
issue-lock-reason: 'resolved'
process-only: 'issues'
log-output: true

View File

@@ -1,66 +0,0 @@
name: client_targets
on:
pull_request:
branches:
- master
paths:
- "client/**"
- "sdk/**"
- ".github/workflows/client-targets.yml"
env:
CARGO_TERM_COLOR: always
jobs:
check_compilation:
name: Client compilation
runs-on: ${{ matrix.os }}
strategy:
matrix:
target: [aarch64-apple-ios, x86_64-apple-ios, aarch64-apple-darwin, x86_64-apple-darwin, aarch64-linux-android, armv7-linux-androideabi, i686-linux-android, x86_64-linux-android]
include:
- target: aarch64-apple-ios
platform: ios
os: macos-latest
- target: x86_64-apple-ios
platform: ios
os: macos-latest
- target: aarch64-apple-darwin
platform: ios
os: macos-latest
- target: x86_64-apple-darwin
platform: ios
os: macos-latest
- target: aarch64-linux-android
platform: android
os: ubuntu-latest
- target: armv7-linux-androideabi
platform: android
os: ubuntu-latest
- target: i686-linux-android
platform: android
os: ubuntu-latest
- target: x86_64-linux-android
platform: android
os: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: ${{ matrix.target }}
- name: Install cargo-ndk
if: ${{ matrix.platform == 'android' }}
run: cargo install cargo-ndk
- uses: actions-rs/cargo@v1
if: ${{ matrix.platform == 'android' }}
with:
command: ndk
args: --target ${{ matrix.target }} build -p solana-client
- uses: actions-rs/cargo@v1
if: ${{ matrix.platform == 'ios' }}
with:
command: build
args: -p solana-client --target ${{ matrix.target }}

View File

@@ -10,49 +10,11 @@ jobs:
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- uses: actions/checkout@v2
with:
ref: ${{ github.event.pull_request.head.sha }}
- uses: amondnet/vercel-action@v20
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }} # Required
github-token: ${{ secrets.GITHUB_TOKEN }} #Optional
vercel-org-id: ${{ secrets.ORG_ID}} #Required
vercel-project-id: ${{ secrets.PROJECT_ID}} #Required
vercel-project-id: ${{ secrets.PROJECT_ID}} #Required
working-directory: ./explorer
scope: ${{ secrets.TEAM_ID }}
- name: vercel url
run : |
touch vercelfile.txt
vercel --token ${{secrets.VERCEL_TOKEN}} ls explorer --scope team_8A2WD7p4uR7tmKX9M68loHXI > vercelfile.txt
touch vercelfile1.txt
head -n 2 vercelfile.txt > vercelfile1.txt
touch vercelfile2.txt
tail -n 1 vercelfile1.txt > vercelfile2.txt
filtered_url7=$(cut -f7 -d" " vercelfile2.txt)
echo "filtered_url7 is: $filtered_url7"
touch .env.preview1
echo "$filtered_url7" > .env.preview1
#filtered_url=$(cat vercelfile2.txt )
#echo "$filtered_url" >> .env.preview1
- name: Fetching Vercel Preview Deployment Link
uses: mathiasvr/command-output@v1
id: test1
with:
run: |
echo "$(cat .env.preview1)"
- name: Fetching PR commit URL
uses: mathiasvr/command-output@v1
id: test2
with:
run: |
HEAD_SHA=$(curl -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/solana-labs/solana/pulls | jq .[0] | jq -r .head.sha)
USER_NAME=$(curl -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/solana-labs/solana/pulls | jq .[0] | jq -r .head.user.login)
echo "github.com/$USER_NAME/solana/commit/$HEAD_SHA"
- name: Slack Notification4
uses: rtCamp/action-slack-notify@master
env:
SLACK_MESSAGE: ' Vercel Link: ${{ steps.test1.outputs.stdout }} PR Commit: ${{steps.test2.outputs.stdout}}'
SLACK_TITLE: Vercel "Explorer" Preview Deployment Link , PR Commit
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

View File

@@ -30,8 +30,7 @@ jobs:
runs-on: ubuntu-latest
defaults:
run:
working-directory: explorer
working-directory: explorer
steps:
- uses: actions/checkout@v2
with:
@@ -39,8 +38,9 @@ jobs:
- uses: amondnet/vercel-action@v20
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }} # Required
github-token: ${{ secrets.PAT }} #Optional
github-token: ${{ secrets.GITHUB_TOKEN }} #Optional
vercel-args: '--prod' #for production
vercel-org-id: ${{ secrets.ORG_ID}} #Required
vercel-project-id: ${{ secrets.PROJECT_ID}} #Required
working-directory: ./explorer
scope: ${{ secrets.TEAM_ID }}

View File

@@ -65,7 +65,20 @@ jobs:
node-version: ${{ matrix.node }}
cache: 'npm'
cache-dependency-path: web3.js/package-lock.json
- run: npm i -g npm@7
- run: npm ci
- run: npm run lint
- run: |
source .travis/before_install.sh
npm install
source .travis/script.sh
npm run build
ls -l lib
test -r lib/index.iife.js
test -r lib/index.cjs.js
test -r lib/index.esm.js
- run: npm run doc
- run: npm run codecov
- run: |
sh -c "$(curl -sSfL https://release.solana.com/edge/install)"
echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH
PATH="$HOME/.local/share/solana/install/active_release/bin:$PATH"
solana --version
- run: npm run test:live-with-test-validator

View File

@@ -24,7 +24,6 @@ pull_request_rules:
- "#approved-reviews-by=0"
- "#commented-reviews-by=0"
- "#changes-requested-reviews-by=0"
- "#review-requested=0"
actions:
request_reviews:
teams:
@@ -35,7 +34,6 @@ pull_request_rules:
- status-success=buildkite/solana
- status-success=ci-gate
- label=automerge
- label!=no-automerge
- author≠@dont-squash-my-commits
- or:
# only require travis success if docs files changed
@@ -62,7 +60,6 @@ pull_request_rules:
- status-success=Travis CI - Pull Request
- status-success=ci-gate
- label=automerge
- label!=no-automerge
- author=@dont-squash-my-commits
- or:
# only require explorer checks if explorer files changed
@@ -96,56 +93,23 @@ pull_request_rules:
- author=mergify[bot]
- head~=^mergify/bp/
- "#status-failure=0"
- "-merged"
- label!=no-automerge
actions:
label:
add:
- automerge
- name: v1.9 feature-gate backport
- name: v1.8 backport
conditions:
- label=v1.9
- label=feature-gate
- label=v1.8
actions:
backport:
ignore_conflicts: true
labels:
- feature-gate
branches:
- v1.9
- name: v1.9 non-feature-gate backport
- v1.8
- name: v1.9 backport
conditions:
- label=v1.9
- label!=feature-gate
actions:
backport:
ignore_conflicts: true
branches:
- v1.9
- name: v1.10 feature-gate backport
conditions:
- label=v1.10
- label=feature-gate
actions:
backport:
ignore_conflicts: true
labels:
- feature-gate
branches:
- v1.10
- name: v1.10 non-feature-gate backport
conditions:
- label=v1.10
- label!=feature-gate
actions:
backport:
ignore_conflicts: true
branches:
- v1.10
commands_restrictions:
# The author of copied PRs is the Mergify user.
# Restrict `copy` access to Core Contributors
copy:
conditions:
- author=@core-contributors

View File

@@ -78,24 +78,6 @@ jobs:
# - sudo apt-get install libssl-dev libudev-dev
# docs pull request
# - name: "explorer"
# if: type = pull_request AND branch = master
# language: node_js
# node_js:
# - "lts/*"
# cache:
# directories:
# - ~/.npm
# before_install:
# - .travis/affects.sh explorer/ .travis || travis_terminate 0
# - cd explorer
# script:
# - npm run build
# - npm run format
- name: "docs"
if: type IN (push, pull_request) OR tag IS present
language: node_js

View File

@@ -74,7 +74,7 @@ minutes to execute. Use that time to write a detailed problem description. Once
the description is written and CI succeeds, click the "Ready to Review" button
and add reviewers. Adding reviewers before CI succeeds is a fast path to losing
reviewer engagement. Not only will they be notified and see the PR is not yet
ready for them, they will also be bombarded with additional notifications
ready for them, they will also be bombarded them with additional notifications
each time you push a commit to get past CI or until they "mute" the PR. Once
muted, you'll need to reach out over some other medium, such as Discord, to
request they have another look. When you use draft PRs, no notifications are
@@ -146,31 +146,6 @@ the subject lines of the git commits contained in the PR. It's especially
generous (and not expected) to rebase or reword commits such that each change
matches the logical flow in your PR description.
### The PR / Issue Labels
Labels make it easier to manage and track PRs / issues. Below some common labels
that we use in Solana. For the complete list of labels, please refer to the
[label page](https://github.com/solana-labs/solana/issues/labels):
* "feature-gate": when you add a new feature gate or modify the behavior of
an existing feature gate, please add the "feature-gate" label to your PR.
New feature gates should also always have a corresponding tracking issue
(go to "New Issue" -> "Feature Gate Tracker [Get Started](https://github.com/solana-labs/solana/issues/new?assignees=&labels=feature-gate&template=1-feature-gate.yml&title=Feature+Gate%3A+)")
and should be updated each time the feature is activated on a cluster.
* "automerge": When a PR is labelled with "automerge", the PR will be
automically merged once CI passes. In general, this label should only
be used for small hot-fix (fewer than 100 lines) or automatic generated
PRs. If you're uncertain, it's usually the case that the PR is not
qualified as "automerge".
* "good first issue": If you happen to find an issue that is non-urgent and
self-contained with moderate scope, you might want to consider attaching
"good first issue" to it as it might be a good practice for newcomers.
* "rust": this pull request updates Rust code.
* "javascript": this pull request updates Javascript code.
### When will my PR be reviewed?
PRs are typically reviewed and merged in under 7 days. If your PR has been open

3182
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,48 +1,49 @@
[workspace]
members = [
"account-decoder",
"accounts-bench",
"accountsdb-plugin-interface",
"accountsdb-plugin-manager",
"accountsdb-plugin-postgres",
"accounts-cluster-bench",
"bench-streamer",
"bench-tps",
"accounts-bench",
"banking-bench",
"banks-client",
"banks-interface",
"banks-server",
"bench-streamer",
"bench-tps",
"bloom",
"bucket_map",
"bloom",
"clap-utils",
"cli",
"cli-config",
"cli-output",
"client",
"client-test",
"core",
"dos",
"download-utils",
"entry",
"faucet",
"frozen-abi",
"perf",
"validator",
"genesis",
"genesis-utils",
"geyser-plugin-interface",
"geyser-plugin-manager",
"gossip",
"install",
"keygen",
"ledger",
"ledger-tool",
"local-cluster",
"log-analyzer",
"logger",
"measure",
"log-analyzer",
"merkle-root-bench",
"merkle-tree",
"storage-bigtable",
"storage-proto",
"streamer",
"measure",
"metrics",
"net-shaper",
"net-utils",
"notifier",
"perf",
"poh",
"poh-bench",
"program-test",
@@ -52,15 +53,11 @@ members = [
"programs/bpf_loader/gen-syscall-list",
"programs/compute-budget",
"programs/config",
"programs/ed25519-tests",
"programs/stake",
"programs/vote",
"programs/zk-token-proof",
"rayon-threadlimit",
"rbpf-cli",
"remote-wallet",
"rpc",
"rpc-test",
"runtime",
"runtime/store-tool",
"sdk",
@@ -68,24 +65,29 @@ members = [
"sdk/cargo-test-bpf",
"send-transaction-service",
"stake-accounts",
"storage-bigtable",
"storage-proto",
"streamer",
"sys-tuner",
"test-validator",
"tokens",
"transaction-dos",
"transaction-status",
"account-decoder",
"upload-perf",
"validator",
"net-utils",
"version",
"cli",
"rayon-threadlimit",
"watchtower",
"zk-token-sdk",
"replica-node",
"replica-lib",
"test-validator",
"rpc-test",
"client-test",
]
exclude = [
"programs/bpf",
]
# This prevents a Travis CI error when building for Windows.
# TODO: Remove once the "simd-accel" feature from the reed-solomon-erasure
# dependency is supported on Apple M1. v2 of the feature resolver is needed to
# specify arch-specific features.
resolver = "2"

View File

@@ -1,4 +1,4 @@
Copyright 2022 Solana Foundation.
Copyright 2020 Solana Foundation.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -35,7 +35,13 @@ On Linux systems you may need to install libssl-dev, pkg-config, zlib1g-dev, etc
```bash
$ sudo apt-get update
$ sudo apt-get install libssl-dev libudev-dev pkg-config zlib1g-dev llvm clang cmake make
$ sudo apt-get install libssl-dev libudev-dev pkg-config zlib1g-dev llvm clang make
```
On Mac M1s, make sure you set up your terminal & homebrew [to use](https://5balloons.info/correct-way-to-install-and-use-homebrew-on-m1-macs/) Rosetta. You can install it with:
```bash
$ softwareupdate --install-rosetta
```
## **2. Download the source code.**
@@ -68,7 +74,7 @@ devnet.solana.com. Runs 24/7. Learn more about the [public clusters](https://doc
# Benchmarking
First, install the nightly build of rustc. `cargo bench` requires the use of the
First install the nightly build of rustc. `cargo bench` requires use of the
unstable features only available in the nightly build.
```bash
@@ -115,12 +121,12 @@ 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
Any content produced by SF or developer resources that SF provides, are
for educational and inspirational 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 the use of
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
@@ -133,7 +139,7 @@ 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
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,

View File

@@ -94,7 +94,7 @@ Alternatively use the Github UI.
```
1. Confirm that your freshly cut release branch is shown as `BETA_CHANNEL` and the previous release branch as `STABLE_CHANNEL`:
```
ci/channel-info.sh
ci/channel_info.sh
```
## Steps to Create a Release
@@ -152,5 +152,5 @@ appearing. To check for progress:
[Crates.io](https://crates.io/crates/solana) should have an updated Solana version. This can take 2-3 hours, and sometimes fails in the `solana-secondary` job.
If this happens and the error is non-fatal, click "Retry" on the "publish crate" job
### Update software on testnet.solana.com
See the documentation at https://github.com/solana-labs/cluster-ops/. devnet.solana.com and mainnet-beta.solana.com run stable releases that have been tested on testnet. Do not update devnet or mainnet-beta with a beta release.
### Update software on devnet.solana.com/testnet.solana.com/mainnet-beta.solana.com
See the documentation at https://github.com/solana-labs/cluster-ops/

View File

@@ -11,7 +11,7 @@
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, typically within 72 hours.
Expect a response as fast as possible, within one business day at the latest.
<a name="bounty"></a>
## Security Bug Bounties

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-account-decoder"
version = "1.11.0"
version = "1.9.5"
description = "Solana account decoder"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@@ -10,21 +10,21 @@ license = "Apache-2.0"
edition = "2021"
[dependencies]
Inflector = "0.11.4"
base64 = "0.13.0"
base64 = "0.12.3"
bincode = "1.3.3"
bs58 = "0.4.0"
bv = "0.11.1"
Inflector = "0.11.4"
lazy_static = "1.4.0"
serde = "1.0.136"
serde = "1.0.130"
serde_derive = "1.0.103"
serde_json = "1.0.79"
solana-config-program = { path = "../programs/config", version = "=1.11.0" }
solana-sdk = { path = "../sdk", version = "=1.11.0" }
solana-vote-program = { path = "../programs/vote", version = "=1.11.0" }
serde_json = "1.0.72"
solana-config-program = { path = "../programs/config", version = "=1.9.5" }
solana-sdk = { path = "../sdk", version = "=1.9.5" }
solana-vote-program = { path = "../programs/vote", version = "=1.9.5" }
spl-token = { version = "=3.2.0", features = ["no-entrypoint"] }
thiserror = "1.0"
zstd = "0.11.1"
zstd = "0.9.0"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -33,7 +33,7 @@ pub type StringDecimals = String;
pub const MAX_BASE58_BYTES: usize = 128;
/// A duplicate representation of an Account for pretty JSON serialization
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct UiAccount {
pub lamports: u64,
@@ -136,13 +136,16 @@ impl UiAccount {
UiAccountData::Binary(blob, encoding) => match encoding {
UiAccountEncoding::Base58 => bs58::decode(blob).into_vec().ok(),
UiAccountEncoding::Base64 => base64::decode(blob).ok(),
UiAccountEncoding::Base64Zstd => base64::decode(blob).ok().and_then(|zstd_data| {
let mut data = vec![];
zstd::stream::read::Decoder::new(zstd_data.as_slice())
.and_then(|mut reader| reader.read_to_end(&mut data))
.map(|_| data)
.ok()
}),
UiAccountEncoding::Base64Zstd => base64::decode(blob)
.ok()
.map(|zstd_data| {
let mut data = vec![];
zstd::stream::read::Decoder::new(zstd_data.as_slice())
.and_then(|mut reader| reader.read_to_end(&mut data))
.map(|_| data)
.ok()
})
.flatten(),
UiAccountEncoding::Binary | UiAccountEncoding::JsonParsed => None,
},
}?;

View File

@@ -5,7 +5,7 @@ use {
parse_nonce::parse_nonce,
parse_stake::parse_stake,
parse_sysvar::parse_sysvar,
parse_token::{parse_token, spl_token_ids},
parse_token::{parse_token, spl_token_id},
parse_vote::parse_vote,
},
inflector::Inflector,
@@ -21,6 +21,7 @@ lazy_static! {
static ref STAKE_PROGRAM_ID: Pubkey = stake::program::id();
static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id();
static ref SYSVAR_PROGRAM_ID: Pubkey = sysvar::id();
static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id();
static ref VOTE_PROGRAM_ID: Pubkey = solana_vote_program::id();
pub static ref PARSABLE_PROGRAM_IDS: HashMap<Pubkey, ParsableAccount> = {
let mut m = HashMap::new();
@@ -30,9 +31,7 @@ lazy_static! {
);
m.insert(*CONFIG_PROGRAM_ID, ParsableAccount::Config);
m.insert(*SYSTEM_PROGRAM_ID, ParsableAccount::Nonce);
for spl_token_id in spl_token_ids() {
m.insert(spl_token_id, ParsableAccount::SplToken);
}
m.insert(*TOKEN_PROGRAM_ID, ParsableAccount::SplToken);
m.insert(*STAKE_PROGRAM_ID, ParsableAccount::Stake);
m.insert(*SYSVAR_PROGRAM_ID, ParsableAccount::Sysvar);
m.insert(*VOTE_PROGRAM_ID, ParsableAccount::Vote);

View File

@@ -15,31 +15,16 @@ use {
// A helper function to convert spl_token::id() as spl_sdk::pubkey::Pubkey to
// solana_sdk::pubkey::Pubkey
fn spl_token_id() -> Pubkey {
pub fn spl_token_id() -> Pubkey {
Pubkey::new_from_array(spl_token::id().to_bytes())
}
// Returns all known SPL Token program ids
pub fn spl_token_ids() -> Vec<Pubkey> {
vec![spl_token_id()]
}
// Check if the provided program id as a known SPL Token program id
pub fn is_known_spl_token_id(program_id: &Pubkey) -> bool {
*program_id == spl_token_id()
}
// A helper function to convert spl_token::native_mint::id() as spl_sdk::pubkey::Pubkey to
// solana_sdk::pubkey::Pubkey
pub fn spl_token_native_mint() -> Pubkey {
Pubkey::new_from_array(spl_token::native_mint::id().to_bytes())
}
// The program id of the `spl_token_native_mint` account
pub fn spl_token_native_mint_program_id() -> Pubkey {
spl_token_id()
}
// A helper function to convert a solana_sdk::pubkey::Pubkey to spl_sdk::pubkey::Pubkey
pub fn spl_token_pubkey(pubkey: &Pubkey) -> SplTokenPubkey {
SplTokenPubkey::new_from_array(pubkey.to_bytes())

View File

@@ -2,21 +2,21 @@
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2021"
name = "solana-accounts-bench"
version = "1.11.0"
version = "1.9.5"
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.14"
rayon = "1.5.1"
solana-logger = { path = "../logger", version = "=1.11.0" }
solana-measure = { path = "../measure", version = "=1.11.0" }
solana-runtime = { path = "../runtime", version = "=1.11.0" }
solana-sdk = { path = "../sdk", version = "=1.11.0" }
solana-version = { path = "../version", version = "=1.11.0" }
solana-logger = { path = "../logger", version = "=1.9.5" }
solana-runtime = { path = "../runtime", version = "=1.9.5" }
solana-measure = { path = "../measure", version = "=1.9.5" }
solana-sdk = { path = "../sdk", version = "=1.9.5" }
solana-version = { path = "../version", version = "=1.9.5" }
clap = "2.33.1"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -6,18 +6,12 @@ use {
rayon::prelude::*,
solana_measure::measure::Measure,
solana_runtime::{
accounts::{
test_utils::{create_test_accounts, update_accounts_bench},
Accounts,
},
accounts::{create_test_accounts, update_accounts_bench, Accounts},
accounts_db::AccountShrinkThreshold,
accounts_index::AccountSecondaryIndexes,
ancestors::Ancestors,
rent_collector::RentCollector,
},
solana_sdk::{
genesis_config::ClusterType, pubkey::Pubkey, sysvar::epoch_schedule::EpochSchedule,
},
solana_sdk::{genesis_config::ClusterType, pubkey::Pubkey},
std::{env, fs, path::PathBuf},
};
@@ -120,12 +114,7 @@ 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,
&EpochSchedule::default(),
&RentCollector::default(),
);
let results = accounts.accounts_db.update_accounts_hash(0, &ancestors);
time.stop();
let mut time_store = Measure::start("hash using store");
let results_store = accounts.accounts_db.update_accounts_hash_with_index_option(
@@ -135,8 +124,7 @@ fn main() {
&ancestors,
None,
false,
&EpochSchedule::default(),
&RentCollector::default(),
None,
false,
);
time_store.stop();

View File

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

View File

@@ -116,7 +116,7 @@ fn make_create_message(
let instructions: Vec<_> = (0..num_instructions)
.into_iter()
.flat_map(|_| {
.map(|_| {
let program_id = if mint.is_some() {
inline_spl_token::id()
} else {
@@ -148,6 +148,7 @@ fn make_create_message(
instructions
})
.flatten()
.collect();
Message::new(&instructions, Some(&keypair.pubkey()))
@@ -673,7 +674,7 @@ pub mod test {
#[test]
fn test_accounts_cluster_bench() {
solana_logger::setup();
let validator_config = ValidatorConfig::default_for_test();
let validator_config = ValidatorConfig::default();
let num_nodes = 1;
let mut config = ClusterConfig {
cluster_lamports: 10_000_000,

View File

@@ -1,19 +1,19 @@
[package]
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2021"
name = "solana-geyser-plugin-interface"
description = "The Solana Geyser plugin interface."
version = "1.11.0"
name = "solana-accountsdb-plugin-interface"
description = "The Solana AccountsDb plugin interface."
version = "1.9.5"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-geyser-plugin-interface"
documentation = "https://docs.rs/solana-accountsdb-plugin-interface"
[dependencies]
log = "0.4.11"
solana-sdk = { path = "../sdk", version = "=1.11.0" }
solana-transaction-status = { path = "../transaction-status", version = "=1.11.0" }
thiserror = "1.0.30"
solana-sdk = { path = "../sdk", version = "=1.9.5" }
solana-transaction-status = { path = "../transaction-status", version = "=1.9.5" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -0,0 +1,20 @@
<p align="center">
<a href="https://solana.com">
<img alt="Solana" src="https://i.imgur.com/IKyzQ6T.png" width="250" />
</a>
</p>
# Solana AccountsDb Plugin Interface
This crate enables an AccountsDb plugin to be plugged into the Solana Validator runtime to take actions
at the time of each account update; for example, saving the account state to an external database. The plugin must implement the `AccountsDbPlugin` trait. Please see the detail of the `accountsdb_plugin_interface.rs` for the interface definition.
The plugin should produce a `cdylib` dynamic library, which must expose a `C` function `_create_plugin()` that
instantiates the implementation of the interface.
The `solana-accountsdb-plugin-postgres` crate provides an example of how to create a plugin which saves the accounts data into an
external PostgreSQL databases.
More information about Solana is available in the [Solana documentation](https://docs.solana.com/).
Still have questions? Ask us on [Discord](https://discordapp.com/invite/pquxPsq)

View File

@@ -1,5 +1,5 @@
/// The interface for Geyser plugins. A plugin must implement
/// the GeyserPlugin trait to work with the runtime.
/// The interface for AccountsDb plugins. A plugin must implement
/// the AccountsDbPlugin trait to work with the runtime.
/// In addition, the dynamic library must export a "C" function _create_plugin which
/// creates the implementation of the plugin.
use {
@@ -9,7 +9,9 @@ use {
thiserror::Error,
};
#[derive(Debug, Clone, PartialEq, Eq)]
impl Eq for ReplicaAccountInfo<'_> {}
#[derive(Clone, PartialEq, Debug)]
/// Information about an account being updated
pub struct ReplicaAccountInfo<'a> {
/// The Pubkey for the account
@@ -85,7 +87,7 @@ pub enum ReplicaBlockInfoVersions<'a> {
/// Errors returned by plugin calls
#[derive(Error, Debug)]
pub enum GeyserPluginError {
pub enum AccountsDbPluginError {
/// Error opening the configuration file; for example, when the file
/// is not found or when the validator process has no permission to read it.
#[error("Error opening config file. Error detail: ({0}).")]
@@ -107,14 +109,10 @@ pub enum GeyserPluginError {
/// Any custom error defined by the plugin.
#[error("Plugin-defined custom error. Error message: ({0})")]
Custom(Box<dyn error::Error + Send + Sync>),
/// Error when updating the transaction.
#[error("Error updating transaction. Error message: ({msg})")]
TransactionUpdateError { msg: String },
}
/// The current status of a slot
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone)]
pub enum SlotStatus {
/// The highest slot of the heaviest fork processed by the node. Ledger state at this slot is
/// not derived from a confirmed or finalized block, but if multiple forks are present, is from
@@ -138,12 +136,12 @@ impl SlotStatus {
}
}
pub type Result<T> = std::result::Result<T, GeyserPluginError>;
pub type Result<T> = std::result::Result<T, AccountsDbPluginError>;
/// Defines a Geyser plugin, to stream data from the runtime.
/// Geyser plugins must describe desired behavior for load and unload,
/// Defines an AccountsDb plugin, to stream data from the runtime.
/// AccountsDb plugins must describe desired behavior for load and unload,
/// as well as how they will handle streamed data.
pub trait GeyserPlugin: Any + Send + Sync + std::fmt::Debug {
pub trait AccountsDbPlugin: Any + Send + Sync + std::fmt::Debug {
fn name(&self) -> &'static str;
/// The callback called when a plugin is loaded by the system,

View File

@@ -0,0 +1 @@
pub mod accountsdb_plugin_interface;

View File

@@ -0,0 +1,31 @@
[package]
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2021"
name = "solana-accountsdb-plugin-manager"
description = "The Solana AccountsDb plugin manager."
version = "1.9.5"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-validator"
[dependencies]
bs58 = "0.4.0"
crossbeam-channel = "0.5"
libloading = "0.7.2"
log = "0.4.11"
serde = "1.0.130"
serde_derive = "1.0.103"
serde_json = "1.0.72"
solana-accountsdb-plugin-interface = { path = "../accountsdb-plugin-interface", version = "=1.9.5" }
solana-logger = { path = "../logger", version = "=1.9.5" }
solana-measure = { path = "../measure", version = "=1.9.5" }
solana-metrics = { path = "../metrics", version = "=1.9.5" }
solana-rpc = { path = "../rpc", version = "=1.9.5" }
solana-runtime = { path = "../runtime", version = "=1.9.5" }
solana-sdk = { path = "../sdk", version = "=1.9.5" }
solana-transaction-status = { path = "../transaction-status", version = "=1.9.5" }
thiserror = "1.0.30"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -1,8 +1,8 @@
/// Module responsible for notifying plugins of account updates
use {
crate::geyser_plugin_manager::GeyserPluginManager,
crate::accountsdb_plugin_manager::AccountsDbPluginManager,
log::*,
solana_geyser_plugin_interface::geyser_plugin_interface::{
solana_accountsdb_plugin_interface::accountsdb_plugin_interface::{
ReplicaAccountInfo, ReplicaAccountInfoVersions,
},
solana_measure::measure::Measure,
@@ -19,7 +19,7 @@ use {
};
#[derive(Debug)]
pub(crate) struct AccountsUpdateNotifierImpl {
plugin_manager: Arc<RwLock<GeyserPluginManager>>,
plugin_manager: Arc<RwLock<AccountsDbPluginManager>>,
}
impl AccountsUpdateNotifierInterface for AccountsUpdateNotifierImpl {
@@ -30,14 +30,14 @@ impl AccountsUpdateNotifierInterface for AccountsUpdateNotifierImpl {
}
fn notify_account_restore_from_snapshot(&self, slot: Slot, account: &StoredAccountMeta) {
let mut measure_all = Measure::start("geyser-plugin-notify-account-restore-all");
let mut measure_copy = Measure::start("geyser-plugin-copy-stored-account-info");
let mut measure_all = Measure::start("accountsdb-plugin-notify-account-restore-all");
let mut measure_copy = Measure::start("accountsdb-plugin-copy-stored-account-info");
let account = self.accountinfo_from_stored_account_meta(account);
measure_copy.stop();
inc_new_counter_debug!(
"geyser-plugin-copy-stored-account-info-us",
"accountsdb-plugin-copy-stored-account-info-us",
measure_copy.as_us() as usize,
100000,
100000
@@ -49,7 +49,7 @@ impl AccountsUpdateNotifierInterface for AccountsUpdateNotifierImpl {
measure_all.stop();
inc_new_counter_debug!(
"geyser-plugin-notify-account-restore-all-us",
"accountsdb-plugin-notify-account-restore-all-us",
measure_all.as_us() as usize,
100000,
100000
@@ -63,7 +63,7 @@ impl AccountsUpdateNotifierInterface for AccountsUpdateNotifierImpl {
}
for plugin in plugin_manager.plugins.iter_mut() {
let mut measure = Measure::start("geyser-plugin-end-of-restore-from-snapshot");
let mut measure = Measure::start("accountsdb-plugin-end-of-restore-from-snapshot");
match plugin.notify_end_of_startup() {
Err(err) => {
error!(
@@ -81,7 +81,7 @@ impl AccountsUpdateNotifierInterface for AccountsUpdateNotifierImpl {
}
measure.stop();
inc_new_counter_debug!(
"geyser-plugin-end-of-restore-from-snapshot",
"accountsdb-plugin-end-of-restore-from-snapshot",
measure.as_us() as usize
);
}
@@ -89,7 +89,7 @@ impl AccountsUpdateNotifierInterface for AccountsUpdateNotifierImpl {
}
impl AccountsUpdateNotifierImpl {
pub fn new(plugin_manager: Arc<RwLock<GeyserPluginManager>>) -> Self {
pub fn new(plugin_manager: Arc<RwLock<AccountsDbPluginManager>>) -> Self {
AccountsUpdateNotifierImpl { plugin_manager }
}
@@ -130,14 +130,14 @@ impl AccountsUpdateNotifierImpl {
slot: Slot,
is_startup: bool,
) {
let mut measure2 = Measure::start("geyser-plugin-notify_plugins_of_account_update");
let mut measure2 = Measure::start("accountsdb-plugin-notify_plugins_of_account_update");
let mut plugin_manager = self.plugin_manager.write().unwrap();
if plugin_manager.plugins.is_empty() {
return;
}
for plugin in plugin_manager.plugins.iter_mut() {
let mut measure = Measure::start("geyser-plugin-update-account");
let mut measure = Measure::start("accountsdb-plugin-update-account");
match plugin.update_account(
ReplicaAccountInfoVersions::V0_0_1(&account),
slot,
@@ -163,7 +163,7 @@ impl AccountsUpdateNotifierImpl {
}
measure.stop();
inc_new_counter_debug!(
"geyser-plugin-update-account-us",
"accountsdb-plugin-update-account-us",
measure.as_us() as usize,
100000,
100000
@@ -171,7 +171,7 @@ impl AccountsUpdateNotifierImpl {
}
measure2.stop();
inc_new_counter_debug!(
"geyser-plugin-notify_plugins_of_account_update-us",
"accountsdb-plugin-notify_plugins_of_account_update-us",
measure2.as_us() as usize,
100000,
100000

View File

@@ -1,20 +1,20 @@
/// Managing the Geyser plugins
/// Managing the AccountsDb plugins
use {
libloading::{Library, Symbol},
log::*,
solana_geyser_plugin_interface::geyser_plugin_interface::GeyserPlugin,
solana_accountsdb_plugin_interface::accountsdb_plugin_interface::AccountsDbPlugin,
std::error::Error,
};
#[derive(Default, Debug)]
pub struct GeyserPluginManager {
pub plugins: Vec<Box<dyn GeyserPlugin>>,
pub struct AccountsDbPluginManager {
pub plugins: Vec<Box<dyn AccountsDbPlugin>>,
libs: Vec<Library>,
}
impl GeyserPluginManager {
impl AccountsDbPluginManager {
pub fn new() -> Self {
GeyserPluginManager {
AccountsDbPluginManager {
plugins: Vec::default(),
libs: Vec::default(),
}
@@ -29,7 +29,7 @@ impl GeyserPluginManager {
libpath: &str,
config_file: &str,
) -> Result<(), Box<dyn Error>> {
type PluginConstructor = unsafe fn() -> *mut dyn GeyserPlugin;
type PluginConstructor = unsafe fn() -> *mut dyn AccountsDbPlugin;
let lib = Library::new(libpath)?;
let constructor: Symbol<PluginConstructor> = lib.get(b"_create_plugin")?;
let plugin_raw = constructor();

View File

@@ -1,13 +1,15 @@
use {
crate::{
accounts_update_notifier::AccountsUpdateNotifierImpl,
accountsdb_plugin_manager::AccountsDbPluginManager,
block_metadata_notifier::BlockMetadataNotifierImpl,
block_metadata_notifier_interface::BlockMetadataNotifierLock,
geyser_plugin_manager::GeyserPluginManager, slot_status_notifier::SlotStatusNotifierImpl,
slot_status_observer::SlotStatusObserver, transaction_notifier::TransactionNotifierImpl,
slot_status_notifier::SlotStatusNotifierImpl, slot_status_observer::SlotStatusObserver,
transaction_notifier::TransactionNotifierImpl,
},
crossbeam_channel::Receiver,
log::*,
serde_json,
solana_rpc::{
optimistically_confirmed_bank_tracker::BankNotification,
transaction_notifier_interface::TransactionNotifierLock,
@@ -24,7 +26,7 @@ use {
};
#[derive(Error, Debug)]
pub enum GeyserPluginServiceError {
pub enum AccountsdbPluginServiceError {
#[error("Cannot open the the plugin config file")]
CannotOpenConfigFile(String),
@@ -44,41 +46,41 @@ pub enum GeyserPluginServiceError {
PluginLoadError(String),
}
/// The service managing the Geyser plugin workflow.
pub struct GeyserPluginService {
/// The service managing the AccountsDb plugin workflow.
pub struct AccountsDbPluginService {
slot_status_observer: Option<SlotStatusObserver>,
plugin_manager: Arc<RwLock<GeyserPluginManager>>,
plugin_manager: Arc<RwLock<AccountsDbPluginManager>>,
accounts_update_notifier: Option<AccountsUpdateNotifier>,
transaction_notifier: Option<TransactionNotifierLock>,
block_metadata_notifier: Option<BlockMetadataNotifierLock>,
}
impl GeyserPluginService {
/// Creates and returns the GeyserPluginService.
impl AccountsDbPluginService {
/// Creates and returns the AccountsDbPluginService.
/// # Arguments
/// * `confirmed_bank_receiver` - The receiver for confirmed bank notification
/// * `geyser_plugin_config_file` - The config file path for the plugin. The
/// * `accountsdb_plugin_config_file` - The config file path for the plugin. The
/// config file controls the plugin responsible
/// for transporting the data to external data stores. It is defined in JSON format.
/// The `libpath` field should be pointed to the full path of the dynamic shared library
/// (.so file) to be loaded. The shared library must implement the `GeyserPlugin`
/// (.so file) to be loaded. The shared library must implement the `AccountsDbPlugin`
/// trait. And the shared library shall export a `C` function `_create_plugin` which
/// shall create the implementation of `GeyserPlugin` and returns to the caller.
/// shall create the implementation of `AccountsDbPlugin` and returns to the caller.
/// The rest of the JSON fields' definition is up to to the concrete plugin implementation
/// It is usually used to configure the connection information for the external data store.
pub fn new(
confirmed_bank_receiver: Receiver<BankNotification>,
geyser_plugin_config_files: &[PathBuf],
) -> Result<Self, GeyserPluginServiceError> {
accountsdb_plugin_config_files: &[PathBuf],
) -> Result<Self, AccountsdbPluginServiceError> {
info!(
"Starting GeyserPluginService from config files: {:?}",
geyser_plugin_config_files
"Starting AccountsDbPluginService from config files: {:?}",
accountsdb_plugin_config_files
);
let mut plugin_manager = GeyserPluginManager::new();
let mut plugin_manager = AccountsDbPluginManager::new();
for geyser_plugin_config_file in geyser_plugin_config_files {
Self::load_plugin(&mut plugin_manager, geyser_plugin_config_file)?;
for accountsdb_plugin_config_file in accountsdb_plugin_config_files {
Self::load_plugin(&mut plugin_manager, accountsdb_plugin_config_file)?;
}
let account_data_notifications_enabled =
plugin_manager.account_data_notifications_enabled();
@@ -122,8 +124,8 @@ impl GeyserPluginService {
(None, None)
};
info!("Started GeyserPluginService");
Ok(GeyserPluginService {
info!("Started AccountsDbPluginService");
Ok(AccountsDbPluginService {
slot_status_observer,
plugin_manager,
accounts_update_notifier,
@@ -133,64 +135,55 @@ impl GeyserPluginService {
}
fn load_plugin(
plugin_manager: &mut GeyserPluginManager,
geyser_plugin_config_file: &Path,
) -> Result<(), GeyserPluginServiceError> {
let mut file = match File::open(geyser_plugin_config_file) {
plugin_manager: &mut AccountsDbPluginManager,
accountsdb_plugin_config_file: &Path,
) -> Result<(), AccountsdbPluginServiceError> {
let mut file = match File::open(accountsdb_plugin_config_file) {
Ok(file) => file,
Err(err) => {
return Err(GeyserPluginServiceError::CannotOpenConfigFile(format!(
return Err(AccountsdbPluginServiceError::CannotOpenConfigFile(format!(
"Failed to open the plugin config file {:?}, error: {:?}",
geyser_plugin_config_file, err
accountsdb_plugin_config_file, err
)));
}
};
let mut contents = String::new();
if let Err(err) = file.read_to_string(&mut contents) {
return Err(GeyserPluginServiceError::CannotReadConfigFile(format!(
return Err(AccountsdbPluginServiceError::CannotReadConfigFile(format!(
"Failed to read the plugin config file {:?}, error: {:?}",
geyser_plugin_config_file, err
accountsdb_plugin_config_file, err
)));
}
let result: serde_json::Value = match json5::from_str(&contents) {
let result: serde_json::Value = match serde_json::from_str(&contents) {
Ok(value) => value,
Err(err) => {
return Err(GeyserPluginServiceError::InvalidConfigFileFormat(format!(
"The config file {:?} is not in a valid Json5 format, error: {:?}",
geyser_plugin_config_file, err
)));
return Err(AccountsdbPluginServiceError::InvalidConfigFileFormat(
format!(
"The config file {:?} is not in a valid Json format, error: {:?}",
accountsdb_plugin_config_file, err
),
));
}
};
let libpath = result["libpath"]
.as_str()
.ok_or(GeyserPluginServiceError::LibPathNotSet)?;
let mut libpath = PathBuf::from(libpath);
if libpath.is_relative() {
let config_dir = geyser_plugin_config_file.parent().ok_or_else(|| {
GeyserPluginServiceError::CannotOpenConfigFile(format!(
"Failed to resolve parent of {:?}",
geyser_plugin_config_file,
))
})?;
libpath = config_dir.join(libpath);
}
let config_file = geyser_plugin_config_file
.ok_or(AccountsdbPluginServiceError::LibPathNotSet)?;
let config_file = accountsdb_plugin_config_file
.as_os_str()
.to_str()
.ok_or(GeyserPluginServiceError::InvalidPluginPath)?;
.ok_or(AccountsdbPluginServiceError::InvalidPluginPath)?;
unsafe {
let result = plugin_manager.load_plugin(libpath.to_str().unwrap(), config_file);
let result = plugin_manager.load_plugin(libpath, config_file);
if let Err(err) = result {
let msg = format!(
"Failed to load the plugin library: {:?}, error: {:?}",
libpath, err
);
return Err(GeyserPluginServiceError::PluginLoadError(msg));
return Err(AccountsdbPluginServiceError::PluginLoadError(msg));
}
}
Ok(())

View File

@@ -1,10 +1,10 @@
use {
crate::{
accountsdb_plugin_manager::AccountsDbPluginManager,
block_metadata_notifier_interface::BlockMetadataNotifier,
geyser_plugin_manager::GeyserPluginManager,
},
log::*,
solana_geyser_plugin_interface::geyser_plugin_interface::{
solana_accountsdb_plugin_interface::accountsdb_plugin_interface::{
ReplicaBlockInfo, ReplicaBlockInfoVersions,
},
solana_measure::measure::Measure,
@@ -16,7 +16,7 @@ use {
};
pub(crate) struct BlockMetadataNotifierImpl {
plugin_manager: Arc<RwLock<GeyserPluginManager>>,
plugin_manager: Arc<RwLock<AccountsDbPluginManager>>,
}
impl BlockMetadataNotifier for BlockMetadataNotifierImpl {
@@ -36,7 +36,7 @@ impl BlockMetadataNotifier for BlockMetadataNotifierImpl {
let rewards = Self::build_rewards(rewards);
for plugin in plugin_manager.plugins.iter_mut() {
let mut measure = Measure::start("geyser-plugin-update-slot");
let mut measure = Measure::start("accountsdb-plugin-update-slot");
let block_info =
Self::build_replica_block_info(slot, blockhash, &rewards, block_time, block_height);
let block_info = ReplicaBlockInfoVersions::V0_0_1(&block_info);
@@ -59,7 +59,7 @@ impl BlockMetadataNotifier for BlockMetadataNotifierImpl {
}
measure.stop();
inc_new_counter_debug!(
"geyser-plugin-update-block-metadata-us",
"accountsdb-plugin-update-block-metadata-us",
measure.as_us() as usize,
1000,
1000
@@ -99,7 +99,7 @@ impl BlockMetadataNotifierImpl {
}
}
pub fn new(plugin_manager: Arc<RwLock<GeyserPluginManager>>) -> Self {
pub fn new(plugin_manager: Arc<RwLock<AccountsDbPluginManager>>) -> Self {
Self { plugin_manager }
}
}

View File

@@ -1,8 +1,8 @@
pub mod accounts_update_notifier;
pub mod accountsdb_plugin_manager;
pub mod accountsdb_plugin_service;
pub mod block_metadata_notifier;
pub mod block_metadata_notifier_interface;
pub mod geyser_plugin_manager;
pub mod geyser_plugin_service;
pub mod slot_status_notifier;
pub mod slot_status_observer;
pub mod transaction_notifier;

View File

@@ -1,7 +1,7 @@
use {
crate::geyser_plugin_manager::GeyserPluginManager,
crate::accountsdb_plugin_manager::AccountsDbPluginManager,
log::*,
solana_geyser_plugin_interface::geyser_plugin_interface::SlotStatus,
solana_accountsdb_plugin_interface::accountsdb_plugin_interface::SlotStatus,
solana_measure::measure::Measure,
solana_metrics::*,
solana_sdk::clock::Slot,
@@ -22,7 +22,7 @@ pub trait SlotStatusNotifierInterface {
pub type SlotStatusNotifier = Arc<RwLock<dyn SlotStatusNotifierInterface + Sync + Send>>;
pub struct SlotStatusNotifierImpl {
plugin_manager: Arc<RwLock<GeyserPluginManager>>,
plugin_manager: Arc<RwLock<AccountsDbPluginManager>>,
}
impl SlotStatusNotifierInterface for SlotStatusNotifierImpl {
@@ -40,7 +40,7 @@ impl SlotStatusNotifierInterface for SlotStatusNotifierImpl {
}
impl SlotStatusNotifierImpl {
pub fn new(plugin_manager: Arc<RwLock<GeyserPluginManager>>) -> Self {
pub fn new(plugin_manager: Arc<RwLock<AccountsDbPluginManager>>) -> Self {
Self { plugin_manager }
}
@@ -51,8 +51,8 @@ impl SlotStatusNotifierImpl {
}
for plugin in plugin_manager.plugins.iter_mut() {
let mut measure = Measure::start("geyser-plugin-update-slot");
match plugin.update_slot_status(slot, parent, slot_status) {
let mut measure = Measure::start("accountsdb-plugin-update-slot");
match plugin.update_slot_status(slot, parent, slot_status.clone()) {
Err(err) => {
error!(
"Failed to update slot status at slot {}, error: {} to plugin {}",
@@ -71,7 +71,7 @@ impl SlotStatusNotifierImpl {
}
measure.stop();
inc_new_counter_debug!(
"geyser-plugin-update-slot-us",
"accountsdb-plugin-update-slot-us",
measure.as_us() as usize,
1000,
1000

View File

@@ -1,8 +1,8 @@
/// Module responsible for notifying plugins of transactions
use {
crate::geyser_plugin_manager::GeyserPluginManager,
crate::accountsdb_plugin_manager::AccountsDbPluginManager,
log::*,
solana_geyser_plugin_interface::geyser_plugin_interface::{
solana_accountsdb_plugin_interface::accountsdb_plugin_interface::{
ReplicaTransactionInfo, ReplicaTransactionInfoVersions,
},
solana_measure::measure::Measure,
@@ -16,9 +16,9 @@ use {
/// This implementation of TransactionNotifier is passed to the rpc's TransactionStatusService
/// at the validator startup. TransactionStatusService invokes the notify_transaction method
/// for new transactions. The implementation in turn invokes the notify_transaction of each
/// plugin enabled with transaction notification managed by the GeyserPluginManager.
/// plugin enabled with transaction notification managed by the AccountsDbPluginManager.
pub(crate) struct TransactionNotifierImpl {
plugin_manager: Arc<RwLock<GeyserPluginManager>>,
plugin_manager: Arc<RwLock<AccountsDbPluginManager>>,
}
impl TransactionNotifier for TransactionNotifierImpl {
@@ -29,7 +29,7 @@ impl TransactionNotifier for TransactionNotifierImpl {
transaction_status_meta: &TransactionStatusMeta,
transaction: &SanitizedTransaction,
) {
let mut measure = Measure::start("geyser-plugin-notify_plugins_of_transaction_info");
let mut measure = Measure::start("accountsdb-plugin-notify_plugins_of_transaction_info");
let transaction_log_info =
Self::build_replica_transaction_info(signature, transaction_status_meta, transaction);
@@ -64,7 +64,7 @@ impl TransactionNotifier for TransactionNotifierImpl {
}
measure.stop();
inc_new_counter_debug!(
"geyser-plugin-notify_plugins_of_transaction_info-us",
"accountsdb-plugin-notify_plugins_of_transaction_info-us",
measure.as_us() as usize,
10000,
10000
@@ -73,7 +73,7 @@ impl TransactionNotifier for TransactionNotifierImpl {
}
impl TransactionNotifierImpl {
pub fn new(plugin_manager: Arc<RwLock<GeyserPluginManager>>) -> Self {
pub fn new(plugin_manager: Arc<RwLock<AccountsDbPluginManager>>) -> Self {
Self { plugin_manager }
}

View File

@@ -0,0 +1,39 @@
[package]
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2021"
name = "solana-accountsdb-plugin-postgres"
description = "The Solana AccountsDb plugin for PostgreSQL database."
version = "1.9.5"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-validator"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
bs58 = "0.4.0"
chrono = { version = "0.4.11", features = ["serde"] }
crossbeam-channel = "0.5"
log = "0.4.14"
postgres = { version = "0.19.2", features = ["with-chrono-0_4"] }
postgres-types = { version = "0.2.2", features = ["derive"] }
serde = "1.0.130"
serde_derive = "1.0.103"
serde_json = "1.0.72"
solana-accountsdb-plugin-interface = { path = "../accountsdb-plugin-interface", version = "=1.9.5" }
solana-logger = { path = "../logger", version = "=1.9.5" }
solana-measure = { path = "../measure", version = "=1.9.5" }
solana-metrics = { path = "../metrics", version = "=1.9.5" }
solana-runtime = { path = "../runtime", version = "=1.9.5" }
solana-sdk = { path = "../sdk", version = "=1.9.5" }
solana-transaction-status = { path = "../transaction-status", version = "=1.9.5" }
thiserror = "1.0.30"
tokio-postgres = "0.7.4"
[dev-dependencies]
solana-account-decoder = { path = "../account-decoder", version = "=1.9.5" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -0,0 +1,5 @@
This is an example implementing the AccountsDb plugin for PostgreSQL database.
Please see the `src/accountsdb_plugin_postgres.rs` for the format of the plugin's configuration file.
To create the schema objects for the database, please use `scripts/create_schema.sql`.
`scripts/drop_schema.sql` can be used to tear down the schema objects.

View File

@@ -0,0 +1,201 @@
/**
* This plugin implementation for PostgreSQL requires the following tables
*/
-- The table storing accounts
CREATE TABLE account (
pubkey BYTEA PRIMARY KEY,
owner BYTEA,
lamports BIGINT NOT NULL,
slot BIGINT NOT NULL,
executable BOOL NOT NULL,
rent_epoch BIGINT NOT NULL,
data BYTEA,
write_version BIGINT NOT NULL,
updated_on TIMESTAMP NOT NULL
);
-- The table storing slot information
CREATE TABLE slot (
slot BIGINT PRIMARY KEY,
parent BIGINT,
status VARCHAR(16) NOT NULL,
updated_on TIMESTAMP NOT NULL
);
-- Types for Transactions
Create TYPE "TransactionErrorCode" AS ENUM (
'AccountInUse',
'AccountLoadedTwice',
'AccountNotFound',
'ProgramAccountNotFound',
'InsufficientFundsForFee',
'InvalidAccountForFee',
'AlreadyProcessed',
'BlockhashNotFound',
'InstructionError',
'CallChainTooDeep',
'MissingSignatureForFee',
'InvalidAccountIndex',
'SignatureFailure',
'InvalidProgramForExecution',
'SanitizeFailure',
'ClusterMaintenance',
'AccountBorrowOutstanding',
'WouldExceedMaxAccountCostLimit',
'WouldExceedMaxBlockCostLimit',
'UnsupportedVersion',
'InvalidWritableAccount',
'WouldExceedMaxAccountDataCostLimit',
'TooManyAccountLocks',
'AddressLookupTableNotFound',
'InvalidAddressLookupTableOwner',
'InvalidAddressLookupTableData',
'InvalidAddressLookupTableIndex',
'InvalidRentPayingAccount'
);
CREATE TYPE "TransactionError" AS (
error_code "TransactionErrorCode",
error_detail VARCHAR(256)
);
CREATE TYPE "CompiledInstruction" AS (
program_id_index SMALLINT,
accounts SMALLINT[],
data BYTEA
);
CREATE TYPE "InnerInstructions" AS (
index SMALLINT,
instructions "CompiledInstruction"[]
);
CREATE TYPE "TransactionTokenBalance" AS (
account_index SMALLINT,
mint VARCHAR(44),
ui_token_amount DOUBLE PRECISION,
owner VARCHAR(44)
);
Create TYPE "RewardType" AS ENUM (
'Fee',
'Rent',
'Staking',
'Voting'
);
CREATE TYPE "Reward" AS (
pubkey VARCHAR(44),
lamports BIGINT,
post_balance BIGINT,
reward_type "RewardType",
commission SMALLINT
);
CREATE TYPE "TransactionStatusMeta" AS (
error "TransactionError",
fee BIGINT,
pre_balances BIGINT[],
post_balances BIGINT[],
inner_instructions "InnerInstructions"[],
log_messages TEXT[],
pre_token_balances "TransactionTokenBalance"[],
post_token_balances "TransactionTokenBalance"[],
rewards "Reward"[]
);
CREATE TYPE "TransactionMessageHeader" AS (
num_required_signatures SMALLINT,
num_readonly_signed_accounts SMALLINT,
num_readonly_unsigned_accounts SMALLINT
);
CREATE TYPE "TransactionMessage" AS (
header "TransactionMessageHeader",
account_keys BYTEA[],
recent_blockhash BYTEA,
instructions "CompiledInstruction"[]
);
CREATE TYPE "TransactionMessageAddressTableLookup" AS (
account_key BYTEA,
writable_indexes SMALLINT[],
readonly_indexes SMALLINT[]
);
CREATE TYPE "TransactionMessageV0" AS (
header "TransactionMessageHeader",
account_keys BYTEA[],
recent_blockhash BYTEA,
instructions "CompiledInstruction"[],
address_table_lookups "TransactionMessageAddressTableLookup"[]
);
CREATE TYPE "LoadedAddresses" AS (
writable BYTEA[],
readonly BYTEA[]
);
CREATE TYPE "LoadedMessageV0" AS (
message "TransactionMessageV0",
loaded_addresses "LoadedAddresses"
);
-- The table storing transactions
CREATE TABLE transaction (
slot BIGINT NOT NULL,
signature BYTEA NOT NULL,
is_vote BOOL NOT NULL,
message_type SMALLINT, -- 0: legacy, 1: v0 message
legacy_message "TransactionMessage",
v0_loaded_message "LoadedMessageV0",
signatures BYTEA[],
message_hash BYTEA,
meta "TransactionStatusMeta",
updated_on TIMESTAMP NOT NULL,
CONSTRAINT transaction_pk PRIMARY KEY (slot, signature)
);
-- The table storing block metadata
CREATE TABLE block (
slot BIGINT PRIMARY KEY,
blockhash VARCHAR(44),
rewards "Reward"[],
block_time BIGINT,
block_height BIGINT,
updated_on TIMESTAMP NOT NULL
);
/**
* The following is for keeping historical data for accounts and is not required for plugin to work.
*/
-- The table storing historical data for accounts
CREATE TABLE account_audit (
pubkey BYTEA,
owner BYTEA,
lamports BIGINT NOT NULL,
slot BIGINT NOT NULL,
executable BOOL NOT NULL,
rent_epoch BIGINT NOT NULL,
data BYTEA,
write_version BIGINT NOT NULL,
updated_on TIMESTAMP NOT NULL
);
CREATE INDEX account_audit_account_key ON account_audit (pubkey, write_version);
CREATE FUNCTION audit_account_update() RETURNS trigger AS $audit_account_update$
BEGIN
INSERT INTO account_audit (pubkey, owner, lamports, slot, executable, rent_epoch, data, write_version, updated_on)
VALUES (OLD.pubkey, OLD.owner, OLD.lamports, OLD.slot,
OLD.executable, OLD.rent_epoch, OLD.data, OLD.write_version, OLD.updated_on);
RETURN NEW;
END;
$audit_account_update$ LANGUAGE plpgsql;
CREATE TRIGGER account_update_trigger AFTER UPDATE OR DELETE ON account
FOR EACH ROW EXECUTE PROCEDURE audit_account_update();

View File

@@ -0,0 +1,26 @@
/**
* Script for cleaning up the schema for PostgreSQL used for the AccountsDb plugin.
*/
DROP TRIGGER account_update_trigger ON account;
DROP FUNCTION audit_account_update;
DROP TABLE account_audit;
DROP TABLE account;
DROP TABLE slot;
DROP TABLE transaction;
DROP TABLE block;
DROP TYPE "TransactionError" CASCADE;
DROP TYPE "TransactionErrorCode" CASCADE;
DROP TYPE "LoadedMessageV0" CASCADE;
DROP TYPE "LoadedAddresses" CASCADE;
DROP TYPE "TransactionMessageV0" CASCADE;
DROP TYPE "TransactionMessage" CASCADE;
DROP TYPE "TransactionMessageHeader" CASCADE;
DROP TYPE "TransactionMessageAddressTableLookup" CASCADE;
DROP TYPE "TransactionStatusMeta" CASCADE;
DROP TYPE "RewardType" CASCADE;
DROP TYPE "Reward" CASCADE;
DROP TYPE "TransactionTokenBalance" CASCADE;
DROP TYPE "InnerInstructions" CASCADE;
DROP TYPE "CompiledInstruction" CASCADE;

View File

@@ -0,0 +1,802 @@
# This a reference configuration file for the PostgreSQL database version 14.
# -----------------------------
# PostgreSQL configuration file
# -----------------------------
#
# This file consists of lines of the form:
#
# name = value
#
# (The "=" is optional.) Whitespace may be used. Comments are introduced with
# "#" anywhere on a line. The complete list of parameter names and allowed
# values can be found in the PostgreSQL documentation.
#
# The commented-out settings shown in this file represent the default values.
# Re-commenting a setting is NOT sufficient to revert it to the default value;
# you need to reload the server.
#
# This file is read on server startup and when the server receives a SIGHUP
# signal. If you edit the file on a running system, you have to SIGHUP the
# server for the changes to take effect, run "pg_ctl reload", or execute
# "SELECT pg_reload_conf()". Some parameters, which are marked below,
# require a server shutdown and restart to take effect.
#
# Any parameter can also be given as a command-line option to the server, e.g.,
# "postgres -c log_connections=on". Some parameters can be changed at run time
# with the "SET" SQL command.
#
# Memory units: B = bytes Time units: us = microseconds
# kB = kilobytes ms = milliseconds
# MB = megabytes s = seconds
# GB = gigabytes min = minutes
# TB = terabytes h = hours
# d = days
#------------------------------------------------------------------------------
# FILE LOCATIONS
#------------------------------------------------------------------------------
# The default values of these variables are driven from the -D command-line
# option or PGDATA environment variable, represented here as ConfigDir.
data_directory = '/var/lib/postgresql/14/main' # use data in another directory
# (change requires restart)
hba_file = '/etc/postgresql/14/main/pg_hba.conf' # host-based authentication file
# (change requires restart)
ident_file = '/etc/postgresql/14/main/pg_ident.conf' # ident configuration file
# (change requires restart)
# If external_pid_file is not explicitly set, no extra PID file is written.
external_pid_file = '/var/run/postgresql/14-main.pid' # write an extra PID file
# (change requires restart)
#------------------------------------------------------------------------------
# CONNECTIONS AND AUTHENTICATION
#------------------------------------------------------------------------------
# - Connection Settings -
#listen_addresses = 'localhost' # what IP address(es) to listen on;
# comma-separated list of addresses;
# defaults to 'localhost'; use '*' for all
# (change requires restart)
listen_addresses = '*'
port = 5433 # (change requires restart)
max_connections = 200 # (change requires restart)
#superuser_reserved_connections = 3 # (change requires restart)
unix_socket_directories = '/var/run/postgresql' # comma-separated list of directories
# (change requires restart)
#unix_socket_group = '' # (change requires restart)
#unix_socket_permissions = 0777 # begin with 0 to use octal notation
# (change requires restart)
#bonjour = off # advertise server via Bonjour
# (change requires restart)
#bonjour_name = '' # defaults to the computer name
# (change requires restart)
# - TCP settings -
# see "man tcp" for details
#tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds;
# 0 selects the system default
#tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds;
# 0 selects the system default
#tcp_keepalives_count = 0 # TCP_KEEPCNT;
# 0 selects the system default
#tcp_user_timeout = 0 # TCP_USER_TIMEOUT, in milliseconds;
# 0 selects the system default
#client_connection_check_interval = 0 # time between checks for client
# disconnection while running queries;
# 0 for never
# - Authentication -
#authentication_timeout = 1min # 1s-600s
#password_encryption = scram-sha-256 # scram-sha-256 or md5
#db_user_namespace = off
# GSSAPI using Kerberos
#krb_server_keyfile = 'FILE:${sysconfdir}/krb5.keytab'
#krb_caseins_users = off
# - SSL -
ssl = on
#ssl_ca_file = ''
ssl_cert_file = '/etc/ssl/certs/ssl-cert-snakeoil.pem'
#ssl_crl_file = ''
#ssl_crl_dir = ''
ssl_key_file = '/etc/ssl/private/ssl-cert-snakeoil.key'
#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
#ssl_prefer_server_ciphers = on
#ssl_ecdh_curve = 'prime256v1'
#ssl_min_protocol_version = 'TLSv1.2'
#ssl_max_protocol_version = ''
#ssl_dh_params_file = ''
#ssl_passphrase_command = ''
#ssl_passphrase_command_supports_reload = off
#------------------------------------------------------------------------------
# RESOURCE USAGE (except WAL)
#------------------------------------------------------------------------------
# - Memory -
shared_buffers = 1GB # min 128kB
# (change requires restart)
#huge_pages = try # on, off, or try
# (change requires restart)
#huge_page_size = 0 # zero for system default
# (change requires restart)
#temp_buffers = 8MB # min 800kB
#max_prepared_transactions = 0 # zero disables the feature
# (change requires restart)
# Caution: it is not advisable to set max_prepared_transactions nonzero unless
# you actively intend to use prepared transactions.
#work_mem = 4MB # min 64kB
#hash_mem_multiplier = 1.0 # 1-1000.0 multiplier on hash table work_mem
#maintenance_work_mem = 64MB # min 1MB
#autovacuum_work_mem = -1 # min 1MB, or -1 to use maintenance_work_mem
#logical_decoding_work_mem = 64MB # min 64kB
#max_stack_depth = 2MB # min 100kB
#shared_memory_type = mmap # the default is the first option
# supported by the operating system:
# mmap
# sysv
# windows
# (change requires restart)
dynamic_shared_memory_type = posix # the default is the first option
# supported by the operating system:
# posix
# sysv
# windows
# mmap
# (change requires restart)
#min_dynamic_shared_memory = 0MB # (change requires restart)
# - Disk -
#temp_file_limit = -1 # limits per-process temp file space
# in kilobytes, or -1 for no limit
# - Kernel Resources -
#max_files_per_process = 1000 # min 64
# (change requires restart)
# - Cost-Based Vacuum Delay -
#vacuum_cost_delay = 0 # 0-100 milliseconds (0 disables)
#vacuum_cost_page_hit = 1 # 0-10000 credits
#vacuum_cost_page_miss = 2 # 0-10000 credits
#vacuum_cost_page_dirty = 20 # 0-10000 credits
#vacuum_cost_limit = 200 # 1-10000 credits
# - Background Writer -
#bgwriter_delay = 200ms # 10-10000ms between rounds
#bgwriter_lru_maxpages = 100 # max buffers written/round, 0 disables
#bgwriter_lru_multiplier = 2.0 # 0-10.0 multiplier on buffers scanned/round
#bgwriter_flush_after = 512kB # measured in pages, 0 disables
# - Asynchronous Behavior -
#backend_flush_after = 0 # measured in pages, 0 disables
effective_io_concurrency = 1000 # 1-1000; 0 disables prefetching
#maintenance_io_concurrency = 10 # 1-1000; 0 disables prefetching
#max_worker_processes = 8 # (change requires restart)
#max_parallel_workers_per_gather = 2 # taken from max_parallel_workers
#max_parallel_maintenance_workers = 2 # taken from max_parallel_workers
#max_parallel_workers = 8 # maximum number of max_worker_processes that
# can be used in parallel operations
#parallel_leader_participation = on
#old_snapshot_threshold = -1 # 1min-60d; -1 disables; 0 is immediate
# (change requires restart)
#------------------------------------------------------------------------------
# WRITE-AHEAD LOG
#------------------------------------------------------------------------------
# - Settings -
wal_level = minimal # minimal, replica, or logical
# (change requires restart)
fsync = off # flush data to disk for crash safety
# (turning this off can cause
# unrecoverable data corruption)
synchronous_commit = off # synchronization level;
# off, local, remote_write, remote_apply, or on
#wal_sync_method = fsync # the default is the first option
# supported by the operating system:
# open_datasync
# fdatasync (default on Linux and FreeBSD)
# fsync
# fsync_writethrough
# open_sync
full_page_writes = off # recover from partial page writes
#wal_log_hints = off # also do full page writes of non-critical updates
# (change requires restart)
#wal_compression = off # enable compression of full-page writes
#wal_init_zero = on # zero-fill new WAL files
#wal_recycle = on # recycle WAL files
#wal_buffers = -1 # min 32kB, -1 sets based on shared_buffers
# (change requires restart)
#wal_writer_delay = 200ms # 1-10000 milliseconds
#wal_writer_flush_after = 1MB # measured in pages, 0 disables
#wal_skip_threshold = 2MB
#commit_delay = 0 # range 0-100000, in microseconds
#commit_siblings = 5 # range 1-1000
# - Checkpoints -
#checkpoint_timeout = 5min # range 30s-1d
#checkpoint_completion_target = 0.9 # checkpoint target duration, 0.0 - 1.0
#checkpoint_flush_after = 256kB # measured in pages, 0 disables
#checkpoint_warning = 30s # 0 disables
max_wal_size = 1GB
min_wal_size = 80MB
# - Archiving -
#archive_mode = off # enables archiving; off, on, or always
# (change requires restart)
#archive_command = '' # command to use to archive a logfile segment
# placeholders: %p = path of file to archive
# %f = file name only
# e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f'
#archive_timeout = 0 # force a logfile segment switch after this
# number of seconds; 0 disables
# - Archive Recovery -
# These are only used in recovery mode.
#restore_command = '' # command to use to restore an archived logfile segment
# placeholders: %p = path of file to restore
# %f = file name only
# e.g. 'cp /mnt/server/archivedir/%f %p'
#archive_cleanup_command = '' # command to execute at every restartpoint
#recovery_end_command = '' # command to execute at completion of recovery
# - Recovery Target -
# Set these only when performing a targeted recovery.
#recovery_target = '' # 'immediate' to end recovery as soon as a
# consistent state is reached
# (change requires restart)
#recovery_target_name = '' # the named restore point to which recovery will proceed
# (change requires restart)
#recovery_target_time = '' # the time stamp up to which recovery will proceed
# (change requires restart)
#recovery_target_xid = '' # the transaction ID up to which recovery will proceed
# (change requires restart)
#recovery_target_lsn = '' # the WAL LSN up to which recovery will proceed
# (change requires restart)
#recovery_target_inclusive = on # Specifies whether to stop:
# just after the specified recovery target (on)
# just before the recovery target (off)
# (change requires restart)
#recovery_target_timeline = 'latest' # 'current', 'latest', or timeline ID
# (change requires restart)
#recovery_target_action = 'pause' # 'pause', 'promote', 'shutdown'
# (change requires restart)
#------------------------------------------------------------------------------
# REPLICATION
#------------------------------------------------------------------------------
# - Sending Servers -
# Set these on the primary and on any standby that will send replication data.
max_wal_senders = 0 # max number of walsender processes
# (change requires restart)
#max_replication_slots = 10 # max number of replication slots
# (change requires restart)
#wal_keep_size = 0 # in megabytes; 0 disables
#max_slot_wal_keep_size = -1 # in megabytes; -1 disables
#wal_sender_timeout = 60s # in milliseconds; 0 disables
#track_commit_timestamp = off # collect timestamp of transaction commit
# (change requires restart)
# - Primary Server -
# These settings are ignored on a standby server.
#synchronous_standby_names = '' # standby servers that provide sync rep
# method to choose sync standbys, number of sync standbys,
# and comma-separated list of application_name
# from standby(s); '*' = all
#vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed
# - Standby Servers -
# These settings are ignored on a primary server.
#primary_conninfo = '' # connection string to sending server
#primary_slot_name = '' # replication slot on sending server
#promote_trigger_file = '' # file name whose presence ends recovery
#hot_standby = on # "off" disallows queries during recovery
# (change requires restart)
#max_standby_archive_delay = 30s # max delay before canceling queries
# when reading WAL from archive;
# -1 allows indefinite delay
#max_standby_streaming_delay = 30s # max delay before canceling queries
# when reading streaming WAL;
# -1 allows indefinite delay
#wal_receiver_create_temp_slot = off # create temp slot if primary_slot_name
# is not set
#wal_receiver_status_interval = 10s # send replies at least this often
# 0 disables
#hot_standby_feedback = off # send info from standby to prevent
# query conflicts
#wal_receiver_timeout = 60s # time that receiver waits for
# communication from primary
# in milliseconds; 0 disables
#wal_retrieve_retry_interval = 5s # time to wait before retrying to
# retrieve WAL after a failed attempt
#recovery_min_apply_delay = 0 # minimum delay for applying changes during recovery
# - Subscribers -
# These settings are ignored on a publisher.
#max_logical_replication_workers = 4 # taken from max_worker_processes
# (change requires restart)
#max_sync_workers_per_subscription = 2 # taken from max_logical_replication_workers
#------------------------------------------------------------------------------
# QUERY TUNING
#------------------------------------------------------------------------------
# - Planner Method Configuration -
#enable_async_append = on
#enable_bitmapscan = on
#enable_gathermerge = on
#enable_hashagg = on
#enable_hashjoin = on
#enable_incremental_sort = on
#enable_indexscan = on
#enable_indexonlyscan = on
#enable_material = on
#enable_memoize = on
#enable_mergejoin = on
#enable_nestloop = on
#enable_parallel_append = on
#enable_parallel_hash = on
#enable_partition_pruning = on
#enable_partitionwise_join = off
#enable_partitionwise_aggregate = off
#enable_seqscan = on
#enable_sort = on
#enable_tidscan = on
# - Planner Cost Constants -
#seq_page_cost = 1.0 # measured on an arbitrary scale
#random_page_cost = 4.0 # same scale as above
#cpu_tuple_cost = 0.01 # same scale as above
#cpu_index_tuple_cost = 0.005 # same scale as above
#cpu_operator_cost = 0.0025 # same scale as above
#parallel_setup_cost = 1000.0 # same scale as above
#parallel_tuple_cost = 0.1 # same scale as above
#min_parallel_table_scan_size = 8MB
#min_parallel_index_scan_size = 512kB
#effective_cache_size = 4GB
#jit_above_cost = 100000 # perform JIT compilation if available
# and query more expensive than this;
# -1 disables
#jit_inline_above_cost = 500000 # inline small functions if query is
# more expensive than this; -1 disables
#jit_optimize_above_cost = 500000 # use expensive JIT optimizations if
# query is more expensive than this;
# -1 disables
# - Genetic Query Optimizer -
#geqo = on
#geqo_threshold = 12
#geqo_effort = 5 # range 1-10
#geqo_pool_size = 0 # selects default based on effort
#geqo_generations = 0 # selects default based on effort
#geqo_selection_bias = 2.0 # range 1.5-2.0
#geqo_seed = 0.0 # range 0.0-1.0
# - Other Planner Options -
#default_statistics_target = 100 # range 1-10000
#constraint_exclusion = partition # on, off, or partition
#cursor_tuple_fraction = 0.1 # range 0.0-1.0
#from_collapse_limit = 8
#jit = on # allow JIT compilation
#join_collapse_limit = 8 # 1 disables collapsing of explicit
# JOIN clauses
#plan_cache_mode = auto # auto, force_generic_plan or
# force_custom_plan
#------------------------------------------------------------------------------
# REPORTING AND LOGGING
#------------------------------------------------------------------------------
# - Where to Log -
#log_destination = 'stderr' # Valid values are combinations of
# stderr, csvlog, syslog, and eventlog,
# depending on platform. csvlog
# requires logging_collector to be on.
# This is used when logging to stderr:
#logging_collector = off # Enable capturing of stderr and csvlog
# into log files. Required to be on for
# csvlogs.
# (change requires restart)
# These are only used if logging_collector is on:
#log_directory = 'log' # directory where log files are written,
# can be absolute or relative to PGDATA
#log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # log file name pattern,
# can include strftime() escapes
#log_file_mode = 0600 # creation mode for log files,
# begin with 0 to use octal notation
#log_rotation_age = 1d # Automatic rotation of logfiles will
# happen after that time. 0 disables.
#log_rotation_size = 10MB # Automatic rotation of logfiles will
# happen after that much log output.
# 0 disables.
#log_truncate_on_rotation = off # If on, an existing log file with the
# same name as the new log file will be
# truncated rather than appended to.
# But such truncation only occurs on
# time-driven rotation, not on restarts
# or size-driven rotation. Default is
# off, meaning append to existing files
# in all cases.
# These are relevant when logging to syslog:
#syslog_facility = 'LOCAL0'
#syslog_ident = 'postgres'
#syslog_sequence_numbers = on
#syslog_split_messages = on
# This is only relevant when logging to eventlog (Windows):
# (change requires restart)
#event_source = 'PostgreSQL'
# - When to Log -
#log_min_messages = warning # values in order of decreasing detail:
# debug5
# debug4
# debug3
# debug2
# debug1
# info
# notice
# warning
# error
# log
# fatal
# panic
#log_min_error_statement = error # values in order of decreasing detail:
# debug5
# debug4
# debug3
# debug2
# debug1
# info
# notice
# warning
# error
# log
# fatal
# panic (effectively off)
#log_min_duration_statement = -1 # -1 is disabled, 0 logs all statements
# and their durations, > 0 logs only
# statements running at least this number
# of milliseconds
#log_min_duration_sample = -1 # -1 is disabled, 0 logs a sample of statements
# and their durations, > 0 logs only a sample of
# statements running at least this number
# of milliseconds;
# sample fraction is determined by log_statement_sample_rate
#log_statement_sample_rate = 1.0 # fraction of logged statements exceeding
# log_min_duration_sample to be logged;
# 1.0 logs all such statements, 0.0 never logs
#log_transaction_sample_rate = 0.0 # fraction of transactions whose statements
# are logged regardless of their duration; 1.0 logs all
# statements from all transactions, 0.0 never logs
# - What to Log -
#debug_print_parse = off
#debug_print_rewritten = off
#debug_print_plan = off
#debug_pretty_print = on
#log_autovacuum_min_duration = -1 # log autovacuum activity;
# -1 disables, 0 logs all actions and
# their durations, > 0 logs only
# actions running at least this number
# of milliseconds.
#log_checkpoints = off
#log_connections = off
#log_disconnections = off
#log_duration = off
#log_error_verbosity = default # terse, default, or verbose messages
#log_hostname = off
log_line_prefix = '%m [%p] %q%u@%d ' # special values:
# %a = application name
# %u = user name
# %d = database name
# %r = remote host and port
# %h = remote host
# %b = backend type
# %p = process ID
# %P = process ID of parallel group leader
# %t = timestamp without milliseconds
# %m = timestamp with milliseconds
# %n = timestamp with milliseconds (as a Unix epoch)
# %Q = query ID (0 if none or not computed)
# %i = command tag
# %e = SQL state
# %c = session ID
# %l = session line number
# %s = session start timestamp
# %v = virtual transaction ID
# %x = transaction ID (0 if none)
# %q = stop here in non-session
# processes
# %% = '%'
# e.g. '<%u%%%d> '
#log_lock_waits = off # log lock waits >= deadlock_timeout
#log_recovery_conflict_waits = off # log standby recovery conflict waits
# >= deadlock_timeout
#log_parameter_max_length = -1 # when logging statements, limit logged
# bind-parameter values to N bytes;
# -1 means print in full, 0 disables
#log_parameter_max_length_on_error = 0 # when logging an error, limit logged
# bind-parameter values to N bytes;
# -1 means print in full, 0 disables
#log_statement = 'none' # none, ddl, mod, all
#log_replication_commands = off
#log_temp_files = -1 # log temporary files equal or larger
# than the specified size in kilobytes;
# -1 disables, 0 logs all temp files
log_timezone = 'Etc/UTC'
#------------------------------------------------------------------------------
# PROCESS TITLE
#------------------------------------------------------------------------------
cluster_name = '14/main' # added to process titles if nonempty
# (change requires restart)
#update_process_title = on
#------------------------------------------------------------------------------
# STATISTICS
#------------------------------------------------------------------------------
# - Query and Index Statistics Collector -
#track_activities = on
#track_activity_query_size = 1024 # (change requires restart)
#track_counts = on
#track_io_timing = off
#track_wal_io_timing = off
#track_functions = none # none, pl, all
stats_temp_directory = '/var/run/postgresql/14-main.pg_stat_tmp'
# - Monitoring -
#compute_query_id = auto
#log_statement_stats = off
#log_parser_stats = off
#log_planner_stats = off
#log_executor_stats = off
#------------------------------------------------------------------------------
# AUTOVACUUM
#------------------------------------------------------------------------------
#autovacuum = on # Enable autovacuum subprocess? 'on'
# requires track_counts to also be on.
#autovacuum_max_workers = 3 # max number of autovacuum subprocesses
# (change requires restart)
#autovacuum_naptime = 1min # time between autovacuum runs
#autovacuum_vacuum_threshold = 50 # min number of row updates before
# vacuum
#autovacuum_vacuum_insert_threshold = 1000 # min number of row inserts
# before vacuum; -1 disables insert
# vacuums
#autovacuum_analyze_threshold = 50 # min number of row updates before
# analyze
#autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum
#autovacuum_vacuum_insert_scale_factor = 0.2 # fraction of inserts over table
# size before insert vacuum
#autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze
#autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum
# (change requires restart)
#autovacuum_multixact_freeze_max_age = 400000000 # maximum multixact age
# before forced vacuum
# (change requires restart)
#autovacuum_vacuum_cost_delay = 2ms # default vacuum cost delay for
# autovacuum, in milliseconds;
# -1 means use vacuum_cost_delay
#autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for
# autovacuum, -1 means use
# vacuum_cost_limit
#------------------------------------------------------------------------------
# CLIENT CONNECTION DEFAULTS
#------------------------------------------------------------------------------
# - Statement Behavior -
#client_min_messages = notice # values in order of decreasing detail:
# debug5
# debug4
# debug3
# debug2
# debug1
# log
# notice
# warning
# error
#search_path = '"$user", public' # schema names
#row_security = on
#default_table_access_method = 'heap'
#default_tablespace = '' # a tablespace name, '' uses the default
#default_toast_compression = 'pglz' # 'pglz' or 'lz4'
#temp_tablespaces = '' # a list of tablespace names, '' uses
# only default tablespace
#check_function_bodies = on
#default_transaction_isolation = 'read committed'
#default_transaction_read_only = off
#default_transaction_deferrable = off
#session_replication_role = 'origin'
#statement_timeout = 0 # in milliseconds, 0 is disabled
#lock_timeout = 0 # in milliseconds, 0 is disabled
#idle_in_transaction_session_timeout = 0 # in milliseconds, 0 is disabled
#idle_session_timeout = 0 # in milliseconds, 0 is disabled
#vacuum_freeze_table_age = 150000000
#vacuum_freeze_min_age = 50000000
#vacuum_failsafe_age = 1600000000
#vacuum_multixact_freeze_table_age = 150000000
#vacuum_multixact_freeze_min_age = 5000000
#vacuum_multixact_failsafe_age = 1600000000
#bytea_output = 'hex' # hex, escape
#xmlbinary = 'base64'
#xmloption = 'content'
#gin_pending_list_limit = 4MB
# - Locale and Formatting -
datestyle = 'iso, mdy'
#intervalstyle = 'postgres'
timezone = 'Etc/UTC'
#timezone_abbreviations = 'Default' # Select the set of available time zone
# abbreviations. Currently, there are
# Default
# Australia (historical usage)
# India
# You can create your own file in
# share/timezonesets/.
#extra_float_digits = 1 # min -15, max 3; any value >0 actually
# selects precise output mode
#client_encoding = sql_ascii # actually, defaults to database
# encoding
# These settings are initialized by initdb, but they can be changed.
lc_messages = 'C.UTF-8' # locale for system error message
# strings
lc_monetary = 'C.UTF-8' # locale for monetary formatting
lc_numeric = 'C.UTF-8' # locale for number formatting
lc_time = 'C.UTF-8' # locale for time formatting
# default configuration for text search
default_text_search_config = 'pg_catalog.english'
# - Shared Library Preloading -
#local_preload_libraries = ''
#session_preload_libraries = ''
#shared_preload_libraries = '' # (change requires restart)
#jit_provider = 'llvmjit' # JIT library to use
# - Other Defaults -
#dynamic_library_path = '$libdir'
#extension_destdir = '' # prepend path when loading extensions
# and shared objects (added by Debian)
#gin_fuzzy_search_limit = 0
#------------------------------------------------------------------------------
# LOCK MANAGEMENT
#------------------------------------------------------------------------------
#deadlock_timeout = 1s
#max_locks_per_transaction = 64 # min 10
# (change requires restart)
#max_pred_locks_per_transaction = 64 # min 10
# (change requires restart)
#max_pred_locks_per_relation = -2 # negative values mean
# (max_pred_locks_per_transaction
# / -max_pred_locks_per_relation) - 1
#max_pred_locks_per_page = 2 # min 0
#------------------------------------------------------------------------------
# VERSION AND PLATFORM COMPATIBILITY
#------------------------------------------------------------------------------
# - Previous PostgreSQL Versions -
#array_nulls = on
#backslash_quote = safe_encoding # on, off, or safe_encoding
#escape_string_warning = on
#lo_compat_privileges = off
#quote_all_identifiers = off
#standard_conforming_strings = on
#synchronize_seqscans = on
# - Other Platforms and Clients -
#transform_null_equals = off
#------------------------------------------------------------------------------
# ERROR HANDLING
#------------------------------------------------------------------------------
#exit_on_error = off # terminate session on any error?
#restart_after_crash = on # reinitialize after backend crash?
#data_sync_retry = off # retry or panic on failure to fsync
# data?
# (change requires restart)
#recovery_init_sync_method = fsync # fsync, syncfs (Linux 5.8+)
#------------------------------------------------------------------------------
# CONFIG FILE INCLUDES
#------------------------------------------------------------------------------
# These options allow settings to be loaded from files other than the
# default postgresql.conf. Note that these are directives, not variable
# assignments, so they can usefully be given more than once.
include_dir = 'conf.d' # include files ending in '.conf' from
# a directory, e.g., 'conf.d'
#include_if_exists = '...' # include file only if it exists
#include = '...' # include file
#------------------------------------------------------------------------------
# CUSTOMIZED OPTIONS
#------------------------------------------------------------------------------
# Add settings for extensions here

View File

@@ -0,0 +1,74 @@
use {log::*, std::collections::HashSet};
#[derive(Debug)]
pub(crate) struct AccountsSelector {
pub accounts: HashSet<Vec<u8>>,
pub owners: HashSet<Vec<u8>>,
pub select_all_accounts: bool,
}
impl AccountsSelector {
pub fn default() -> Self {
AccountsSelector {
accounts: HashSet::default(),
owners: HashSet::default(),
select_all_accounts: true,
}
}
pub fn new(accounts: &[String], owners: &[String]) -> Self {
info!(
"Creating AccountsSelector from accounts: {:?}, owners: {:?}",
accounts, owners
);
let select_all_accounts = accounts.iter().any(|key| key == "*");
if select_all_accounts {
return AccountsSelector {
accounts: HashSet::default(),
owners: HashSet::default(),
select_all_accounts,
};
}
let accounts = accounts
.iter()
.map(|key| bs58::decode(key).into_vec().unwrap())
.collect();
let owners = owners
.iter()
.map(|key| bs58::decode(key).into_vec().unwrap())
.collect();
AccountsSelector {
accounts,
owners,
select_all_accounts,
}
}
pub fn is_account_selected(&self, account: &[u8], owner: &[u8]) -> bool {
self.select_all_accounts || self.accounts.contains(account) || self.owners.contains(owner)
}
/// Check if any account is of interested at all
pub fn is_enabled(&self) -> bool {
self.select_all_accounts || !self.accounts.is_empty() || !self.owners.is_empty()
}
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
#[test]
fn test_create_accounts_selector() {
AccountsSelector::new(
&["9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin".to_string()],
&[],
);
AccountsSelector::new(
&[],
&["9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin".to_string()],
);
}
}

View File

@@ -0,0 +1,466 @@
use solana_measure::measure::Measure;
/// Main entry for the PostgreSQL plugin
use {
crate::{
accounts_selector::AccountsSelector,
postgres_client::{ParallelPostgresClient, PostgresClientBuilder},
transaction_selector::TransactionSelector,
},
bs58,
log::*,
serde_derive::{Deserialize, Serialize},
serde_json,
solana_accountsdb_plugin_interface::accountsdb_plugin_interface::{
AccountsDbPlugin, AccountsDbPluginError, ReplicaAccountInfoVersions,
ReplicaBlockInfoVersions, ReplicaTransactionInfoVersions, Result, SlotStatus,
},
solana_metrics::*,
std::{fs::File, io::Read},
thiserror::Error,
};
#[derive(Default)]
pub struct AccountsDbPluginPostgres {
client: Option<ParallelPostgresClient>,
accounts_selector: Option<AccountsSelector>,
transaction_selector: Option<TransactionSelector>,
}
impl std::fmt::Debug for AccountsDbPluginPostgres {
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct AccountsDbPluginPostgresConfig {
pub host: Option<String>,
pub user: Option<String>,
pub port: Option<u16>,
pub connection_str: Option<String>,
pub threads: Option<usize>,
pub batch_size: Option<usize>,
pub panic_on_db_errors: Option<bool>,
/// Indicates if to store historical data for accounts
pub store_account_historical_data: Option<bool>,
}
#[derive(Error, Debug)]
pub enum AccountsDbPluginPostgresError {
#[error("Error connecting to the backend data store. Error message: ({msg})")]
DataStoreConnectionError { msg: String },
#[error("Error preparing data store schema. Error message: ({msg})")]
DataSchemaError { msg: String },
#[error("Error preparing data store schema. Error message: ({msg})")]
ConfigurationError { msg: String },
}
impl AccountsDbPlugin for AccountsDbPluginPostgres {
fn name(&self) -> &'static str {
"AccountsDbPluginPostgres"
}
/// Do initialization for the PostgreSQL plugin.
///
/// # Format of the config file:
/// * The `accounts_selector` section allows the user to controls accounts selections.
/// "accounts_selector" : {
/// "accounts" : \["pubkey-1", "pubkey-2", ..., "pubkey-n"\],
/// }
/// or:
/// "accounts_selector" = {
/// "owners" : \["pubkey-1", "pubkey-2", ..., "pubkey-m"\]
/// }
/// Accounts either satisyfing the accounts condition or owners condition will be selected.
/// When only owners is specified,
/// all accounts belonging to the owners will be streamed.
/// The accounts field supports wildcard to select all accounts:
/// "accounts_selector" : {
/// "accounts" : \["*"\],
/// }
/// * "host", optional, specifies the PostgreSQL server.
/// * "user", optional, specifies the PostgreSQL user.
/// * "port", optional, specifies the PostgreSQL server's port.
/// * "connection_str", optional, the custom PostgreSQL connection string.
/// Please refer to https://docs.rs/postgres/0.19.2/postgres/config/struct.Config.html for the connection configuration.
/// When `connection_str` is set, the values in "host", "user" and "port" are ignored. If `connection_str` is not given,
/// `host` and `user` must be given.
/// "store_account_historical_data", optional, set it to 'true', to store historical account data to account_audit
/// table.
/// * "threads" optional, specifies the number of worker threads for the plugin. A thread
/// maintains a PostgreSQL connection to the server. The default is '10'.
/// * "batch_size" optional, specifies the batch size of bulk insert when the AccountsDb is created
/// from restoring a snapshot. The default is '10'.
/// * "panic_on_db_errors", optional, contols if to panic when there are errors replicating data to the
/// PostgreSQL database. The default is 'false'.
/// * "transaction_selector", optional, controls if and what transaction to store. If this field is missing
/// None of the transction is stored.
/// "transaction_selector" : {
/// "mentions" : \["pubkey-1", "pubkey-2", ..., "pubkey-n"\],
/// }
/// The `mentions` field support wildcard to select all transaction or all 'vote' transactions:
/// For example, to select all transactions:
/// "transaction_selector" : {
/// "mentions" : \["*"\],
/// }
/// To select all vote transactions:
/// "transaction_selector" : {
/// "mentions" : \["all_votes"\],
/// }
/// # Examples
///
/// {
/// "libpath": "/home/solana/target/release/libsolana_accountsdb_plugin_postgres.so",
/// "host": "host_foo",
/// "user": "solana",
/// "threads": 10,
/// "accounts_selector" : {
/// "owners" : ["9oT9R5ZyRovSVnt37QvVoBttGpNqR3J7unkb567NP8k3"]
/// }
/// }
fn on_load(&mut self, config_file: &str) -> Result<()> {
solana_logger::setup_with_default("info");
info!(
"Loading plugin {:?} from config_file {:?}",
self.name(),
config_file
);
let mut file = File::open(config_file)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
let result: serde_json::Value = serde_json::from_str(&contents).unwrap();
self.accounts_selector = Some(Self::create_accounts_selector_from_config(&result));
self.transaction_selector = Some(Self::create_transaction_selector_from_config(&result));
let result: serde_json::Result<AccountsDbPluginPostgresConfig> =
serde_json::from_str(&contents);
match result {
Err(err) => {
return Err(AccountsDbPluginError::ConfigFileReadError {
msg: format!(
"The config file is not in the JSON format expected: {:?}",
err
),
})
}
Ok(config) => {
let client = PostgresClientBuilder::build_pararallel_postgres_client(&config)?;
self.client = Some(client);
}
}
Ok(())
}
fn on_unload(&mut self) {
info!("Unloading plugin: {:?}", self.name());
match &mut self.client {
None => {}
Some(client) => {
client.join().unwrap();
}
}
}
fn update_account(
&mut self,
account: ReplicaAccountInfoVersions,
slot: u64,
is_startup: bool,
) -> Result<()> {
let mut measure_all = Measure::start("accountsdb-plugin-postgres-update-account-main");
match account {
ReplicaAccountInfoVersions::V0_0_1(account) => {
let mut measure_select =
Measure::start("accountsdb-plugin-postgres-update-account-select");
if let Some(accounts_selector) = &self.accounts_selector {
if !accounts_selector.is_account_selected(account.pubkey, account.owner) {
return Ok(());
}
} else {
return Ok(());
}
measure_select.stop();
inc_new_counter_debug!(
"accountsdb-plugin-postgres-update-account-select-us",
measure_select.as_us() as usize,
100000,
100000
);
debug!(
"Updating account {:?} with owner {:?} at slot {:?} using account selector {:?}",
bs58::encode(account.pubkey).into_string(),
bs58::encode(account.owner).into_string(),
slot,
self.accounts_selector.as_ref().unwrap()
);
match &mut self.client {
None => {
return Err(AccountsDbPluginError::Custom(Box::new(
AccountsDbPluginPostgresError::DataStoreConnectionError {
msg: "There is no connection to the PostgreSQL database."
.to_string(),
},
)));
}
Some(client) => {
let mut measure_update =
Measure::start("accountsdb-plugin-postgres-update-account-client");
let result = { client.update_account(account, slot, is_startup) };
measure_update.stop();
inc_new_counter_debug!(
"accountsdb-plugin-postgres-update-account-client-us",
measure_update.as_us() as usize,
100000,
100000
);
if let Err(err) = result {
return Err(AccountsDbPluginError::AccountsUpdateError {
msg: format!("Failed to persist the update of account to the PostgreSQL database. Error: {:?}", err)
});
}
}
}
}
}
measure_all.stop();
inc_new_counter_debug!(
"accountsdb-plugin-postgres-update-account-main-us",
measure_all.as_us() as usize,
100000,
100000
);
Ok(())
}
fn update_slot_status(
&mut self,
slot: u64,
parent: Option<u64>,
status: SlotStatus,
) -> Result<()> {
info!("Updating slot {:?} at with status {:?}", slot, status);
match &mut self.client {
None => {
return Err(AccountsDbPluginError::Custom(Box::new(
AccountsDbPluginPostgresError::DataStoreConnectionError {
msg: "There is no connection to the PostgreSQL database.".to_string(),
},
)));
}
Some(client) => {
let result = client.update_slot_status(slot, parent, status);
if let Err(err) = result {
return Err(AccountsDbPluginError::SlotStatusUpdateError{
msg: format!("Failed to persist the update of slot to the PostgreSQL database. Error: {:?}", err)
});
}
}
}
Ok(())
}
fn notify_end_of_startup(&mut self) -> Result<()> {
info!("Notifying the end of startup for accounts notifications");
match &mut self.client {
None => {
return Err(AccountsDbPluginError::Custom(Box::new(
AccountsDbPluginPostgresError::DataStoreConnectionError {
msg: "There is no connection to the PostgreSQL database.".to_string(),
},
)));
}
Some(client) => {
let result = client.notify_end_of_startup();
if let Err(err) = result {
return Err(AccountsDbPluginError::SlotStatusUpdateError{
msg: format!("Failed to notify the end of startup for accounts notifications. Error: {:?}", err)
});
}
}
}
Ok(())
}
fn notify_transaction(
&mut self,
transaction_info: ReplicaTransactionInfoVersions,
slot: u64,
) -> Result<()> {
match &mut self.client {
None => {
return Err(AccountsDbPluginError::Custom(Box::new(
AccountsDbPluginPostgresError::DataStoreConnectionError {
msg: "There is no connection to the PostgreSQL database.".to_string(),
},
)));
}
Some(client) => match transaction_info {
ReplicaTransactionInfoVersions::V0_0_1(transaction_info) => {
if let Some(transaction_selector) = &self.transaction_selector {
if !transaction_selector.is_transaction_selected(
transaction_info.is_vote,
transaction_info.transaction.message().account_keys_iter(),
) {
return Ok(());
}
} else {
return Ok(());
}
let result = client.log_transaction_info(transaction_info, slot);
if let Err(err) = result {
return Err(AccountsDbPluginError::SlotStatusUpdateError{
msg: format!("Failed to persist the transaction info to the PostgreSQL database. Error: {:?}", err)
});
}
}
},
}
Ok(())
}
fn notify_block_metadata(&mut self, block_info: ReplicaBlockInfoVersions) -> Result<()> {
match &mut self.client {
None => {
return Err(AccountsDbPluginError::Custom(Box::new(
AccountsDbPluginPostgresError::DataStoreConnectionError {
msg: "There is no connection to the PostgreSQL database.".to_string(),
},
)));
}
Some(client) => match block_info {
ReplicaBlockInfoVersions::V0_0_1(block_info) => {
let result = client.update_block_metadata(block_info);
if let Err(err) = result {
return Err(AccountsDbPluginError::SlotStatusUpdateError{
msg: format!("Failed to persist the update of block metadata to the PostgreSQL database. Error: {:?}", err)
});
}
}
},
}
Ok(())
}
/// Check if the plugin is interested in account data
/// Default is true -- if the plugin is not interested in
/// account data, please return false.
fn account_data_notifications_enabled(&self) -> bool {
self.accounts_selector
.as_ref()
.map_or_else(|| false, |selector| selector.is_enabled())
}
/// Check if the plugin is interested in transaction data
fn transaction_notifications_enabled(&self) -> bool {
self.transaction_selector
.as_ref()
.map_or_else(|| false, |selector| selector.is_enabled())
}
}
impl AccountsDbPluginPostgres {
fn create_accounts_selector_from_config(config: &serde_json::Value) -> AccountsSelector {
let accounts_selector = &config["accounts_selector"];
if accounts_selector.is_null() {
AccountsSelector::default()
} else {
let accounts = &accounts_selector["accounts"];
let accounts: Vec<String> = if accounts.is_array() {
accounts
.as_array()
.unwrap()
.iter()
.map(|val| val.as_str().unwrap().to_string())
.collect()
} else {
Vec::default()
};
let owners = &accounts_selector["owners"];
let owners: Vec<String> = if owners.is_array() {
owners
.as_array()
.unwrap()
.iter()
.map(|val| val.as_str().unwrap().to_string())
.collect()
} else {
Vec::default()
};
AccountsSelector::new(&accounts, &owners)
}
}
fn create_transaction_selector_from_config(config: &serde_json::Value) -> TransactionSelector {
let transaction_selector = &config["transaction_selector"];
if transaction_selector.is_null() {
TransactionSelector::default()
} else {
let accounts = &transaction_selector["mentions"];
let accounts: Vec<String> = if accounts.is_array() {
accounts
.as_array()
.unwrap()
.iter()
.map(|val| val.as_str().unwrap().to_string())
.collect()
} else {
Vec::default()
};
TransactionSelector::new(&accounts)
}
}
pub fn new() -> Self {
Self::default()
}
}
#[no_mangle]
#[allow(improper_ctypes_definitions)]
/// # Safety
///
/// This function returns the AccountsDbPluginPostgres pointer as trait AccountsDbPlugin.
pub unsafe extern "C" fn _create_plugin() -> *mut dyn AccountsDbPlugin {
let plugin = AccountsDbPluginPostgres::new();
let plugin: Box<dyn AccountsDbPlugin> = Box::new(plugin);
Box::into_raw(plugin)
}
#[cfg(test)]
pub(crate) mod tests {
use {super::*, serde_json};
#[test]
fn test_accounts_selector_from_config() {
let config = "{\"accounts_selector\" : { \
\"owners\" : [\"9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin\"] \
}}";
let config: serde_json::Value = serde_json::from_str(config).unwrap();
AccountsDbPluginPostgres::create_accounts_selector_from_config(&config);
}
}

View File

@@ -0,0 +1,4 @@
pub mod accounts_selector;
pub mod accountsdb_plugin_postgres;
pub mod postgres_client;
pub mod transaction_selector;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,97 @@
use {
crate::{
accountsdb_plugin_postgres::{
AccountsDbPluginPostgresConfig, AccountsDbPluginPostgresError,
},
postgres_client::{
postgres_client_transaction::DbReward, SimplePostgresClient, UpdateBlockMetadataRequest,
},
},
chrono::Utc,
log::*,
postgres::{Client, Statement},
solana_accountsdb_plugin_interface::accountsdb_plugin_interface::{
AccountsDbPluginError, ReplicaBlockInfo,
},
};
#[derive(Clone, Debug)]
pub struct DbBlockInfo {
pub slot: i64,
pub blockhash: String,
pub rewards: Vec<DbReward>,
pub block_time: Option<i64>,
pub block_height: Option<i64>,
}
impl<'a> From<&ReplicaBlockInfo<'a>> for DbBlockInfo {
fn from(block_info: &ReplicaBlockInfo) -> Self {
Self {
slot: block_info.slot as i64,
blockhash: block_info.blockhash.to_string(),
rewards: block_info.rewards.iter().map(DbReward::from).collect(),
block_time: block_info.block_time,
block_height: block_info
.block_height
.map(|block_height| block_height as i64),
}
}
}
impl SimplePostgresClient {
pub(crate) fn build_block_metadata_upsert_statement(
client: &mut Client,
config: &AccountsDbPluginPostgresConfig,
) -> Result<Statement, AccountsDbPluginError> {
let stmt =
"INSERT INTO block (slot, blockhash, rewards, block_time, block_height, updated_on) \
VALUES ($1, $2, $3, $4, $5, $6)";
let stmt = client.prepare(stmt);
match stmt {
Err(err) => {
return Err(AccountsDbPluginError::Custom(Box::new(AccountsDbPluginPostgresError::DataSchemaError {
msg: format!(
"Error in preparing for the block metadata update PostgreSQL database: ({}) host: {:?} user: {:?} config: {:?}",
err, config.host, config.user, config
),
})));
}
Ok(stmt) => Ok(stmt),
}
}
pub(crate) fn update_block_metadata_impl(
&mut self,
block_info: UpdateBlockMetadataRequest,
) -> Result<(), AccountsDbPluginError> {
let client = self.client.get_mut().unwrap();
let statement = &client.update_block_metadata_stmt;
let client = &mut client.client;
let updated_on = Utc::now().naive_utc();
let block_info = block_info.block_info;
let result = client.query(
statement,
&[
&block_info.slot,
&block_info.blockhash,
&block_info.rewards,
&block_info.block_time,
&block_info.block_height,
&updated_on,
],
);
if let Err(err) = result {
let msg = format!(
"Failed to persist the update of block metadata to the PostgreSQL database. Error: {:?}",
err);
error!("{}", msg);
return Err(AccountsDbPluginError::AccountsUpdateError { msg });
}
Ok(())
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,194 @@
/// The transaction selector is responsible for filtering transactions
/// in the plugin framework.
use {log::*, solana_sdk::pubkey::Pubkey, std::collections::HashSet};
pub(crate) struct TransactionSelector {
pub mentioned_addresses: HashSet<Vec<u8>>,
pub select_all_transactions: bool,
pub select_all_vote_transactions: bool,
}
#[allow(dead_code)]
impl TransactionSelector {
pub fn default() -> Self {
Self {
mentioned_addresses: HashSet::default(),
select_all_transactions: false,
select_all_vote_transactions: false,
}
}
/// Create a selector based on the mentioned addresses
/// To select all transactions use ["*"] or ["all"]
/// To select all vote transactions, use ["all_votes"]
/// To select transactions mentioning specific addresses use ["<pubkey1>", "<pubkey2>", ...]
pub fn new(mentioned_addresses: &[String]) -> Self {
info!(
"Creating TransactionSelector from addresses: {:?}",
mentioned_addresses
);
let select_all_transactions = mentioned_addresses
.iter()
.any(|key| key == "*" || key == "all");
if select_all_transactions {
return Self {
mentioned_addresses: HashSet::default(),
select_all_transactions,
select_all_vote_transactions: true,
};
}
let select_all_vote_transactions = mentioned_addresses.iter().any(|key| key == "all_votes");
if select_all_vote_transactions {
return Self {
mentioned_addresses: HashSet::default(),
select_all_transactions,
select_all_vote_transactions: true,
};
}
let mentioned_addresses = mentioned_addresses
.iter()
.map(|key| bs58::decode(key).into_vec().unwrap())
.collect();
Self {
mentioned_addresses,
select_all_transactions: false,
select_all_vote_transactions: false,
}
}
/// Check if a transaction is of interest.
pub fn is_transaction_selected(
&self,
is_vote: bool,
mentioned_addresses: Box<dyn Iterator<Item = &Pubkey> + '_>,
) -> bool {
if !self.is_enabled() {
return false;
}
if self.select_all_transactions || (self.select_all_vote_transactions && is_vote) {
return true;
}
for address in mentioned_addresses {
if self.mentioned_addresses.contains(address.as_ref()) {
return true;
}
}
false
}
/// Check if any transaction is of interest at all
pub fn is_enabled(&self) -> bool {
self.select_all_transactions
|| self.select_all_vote_transactions
|| !self.mentioned_addresses.is_empty()
}
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
#[test]
fn test_select_transaction() {
let pubkey1 = Pubkey::new_unique();
let pubkey2 = Pubkey::new_unique();
let selector = TransactionSelector::new(&[pubkey1.to_string()]);
assert!(selector.is_enabled());
let addresses = [pubkey1];
assert!(selector.is_transaction_selected(false, Box::new(addresses.iter())));
let addresses = [pubkey2];
assert!(!selector.is_transaction_selected(false, Box::new(addresses.iter())));
let addresses = [pubkey1, pubkey2];
assert!(selector.is_transaction_selected(false, Box::new(addresses.iter())));
}
#[test]
fn test_select_all_transaction_using_wildcard() {
let pubkey1 = Pubkey::new_unique();
let pubkey2 = Pubkey::new_unique();
let selector = TransactionSelector::new(&["*".to_string()]);
assert!(selector.is_enabled());
let addresses = [pubkey1];
assert!(selector.is_transaction_selected(false, Box::new(addresses.iter())));
let addresses = [pubkey2];
assert!(selector.is_transaction_selected(false, Box::new(addresses.iter())));
let addresses = [pubkey1, pubkey2];
assert!(selector.is_transaction_selected(false, Box::new(addresses.iter())));
}
#[test]
fn test_select_all_transaction_all() {
let pubkey1 = Pubkey::new_unique();
let pubkey2 = Pubkey::new_unique();
let selector = TransactionSelector::new(&["all".to_string()]);
assert!(selector.is_enabled());
let addresses = [pubkey1];
assert!(selector.is_transaction_selected(false, Box::new(addresses.iter())));
let addresses = [pubkey2];
assert!(selector.is_transaction_selected(false, Box::new(addresses.iter())));
let addresses = [pubkey1, pubkey2];
assert!(selector.is_transaction_selected(false, Box::new(addresses.iter())));
}
#[test]
fn test_select_all_vote_transaction() {
let pubkey1 = Pubkey::new_unique();
let pubkey2 = Pubkey::new_unique();
let selector = TransactionSelector::new(&["all_votes".to_string()]);
assert!(selector.is_enabled());
let addresses = [pubkey1];
assert!(!selector.is_transaction_selected(false, Box::new(addresses.iter())));
let addresses = [pubkey2];
assert!(selector.is_transaction_selected(true, Box::new(addresses.iter())));
let addresses = [pubkey1, pubkey2];
assert!(selector.is_transaction_selected(true, Box::new(addresses.iter())));
}
#[test]
fn test_select_no_transaction() {
let pubkey1 = Pubkey::new_unique();
let pubkey2 = Pubkey::new_unique();
let selector = TransactionSelector::new(&[]);
assert!(!selector.is_enabled());
let addresses = [pubkey1];
assert!(!selector.is_transaction_selected(false, Box::new(addresses.iter())));
let addresses = [pubkey2];
assert!(!selector.is_transaction_selected(true, Box::new(addresses.iter())));
let addresses = [pubkey1, pubkey2];
assert!(!selector.is_transaction_selected(true, Box::new(addresses.iter())));
}
}

View File

@@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2021"
name = "solana-banking-bench"
version = "1.11.0"
version = "1.9.5"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@@ -14,17 +14,17 @@ crossbeam-channel = "0.5"
log = "0.4.14"
rand = "0.7.0"
rayon = "1.5.1"
solana-core = { path = "../core", version = "=1.11.0" }
solana-gossip = { path = "../gossip", version = "=1.11.0" }
solana-ledger = { path = "../ledger", version = "=1.11.0" }
solana-logger = { path = "../logger", version = "=1.11.0" }
solana-measure = { path = "../measure", version = "=1.11.0" }
solana-perf = { path = "../perf", version = "=1.11.0" }
solana-poh = { path = "../poh", version = "=1.11.0" }
solana-runtime = { path = "../runtime", version = "=1.11.0" }
solana-sdk = { path = "../sdk", version = "=1.11.0" }
solana-streamer = { path = "../streamer", version = "=1.11.0" }
solana-version = { path = "../version", version = "=1.11.0" }
solana-core = { path = "../core", version = "=1.9.5" }
solana-gossip = { path = "../gossip", version = "=1.9.5" }
solana-ledger = { path = "../ledger", version = "=1.9.5" }
solana-logger = { path = "../logger", version = "=1.9.5" }
solana-measure = { path = "../measure", version = "=1.9.5" }
solana-perf = { path = "../perf", version = "=1.9.5" }
solana-poh = { path = "../poh", version = "=1.9.5" }
solana-runtime = { path = "../runtime", version = "=1.9.5" }
solana-streamer = { path = "../streamer", version = "=1.9.5" }
solana-sdk = { path = "../sdk", version = "=1.9.5" }
solana-version = { path = "../version", version = "=1.9.5" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -1,7 +1,7 @@
#![allow(clippy::integer_arithmetic)]
use {
clap::{crate_description, crate_name, value_t, App, Arg},
crossbeam_channel::{unbounded, Receiver},
crossbeam_channel::unbounded,
log::*,
rand::{thread_rng, Rng},
rayon::prelude::*,
@@ -11,7 +11,6 @@ use {
blockstore::Blockstore,
genesis_utils::{create_genesis_config, GenesisConfigInfo},
get_tmp_ledger_path,
leader_schedule_cache::LeaderScheduleCache,
},
solana_measure::measure::Measure,
solana_perf::packet::to_packet_batches,
@@ -29,7 +28,7 @@ use {
},
solana_streamer::socket::SocketAddrSpace,
std::{
sync::{atomic::Ordering, Arc, Mutex, RwLock},
sync::{atomic::Ordering, mpsc::Receiver, Arc, Mutex, RwLock},
thread::sleep,
time::{Duration, Instant},
},
@@ -175,11 +174,6 @@ fn main() {
let mut bank_forks = BankForks::new(bank0);
let mut bank = bank_forks.working_bank();
// set cost tracker limits to MAX so it will not filter out TXs
bank.write_cost_tracker()
.unwrap()
.set_limits(std::u64::MAX, std::u64::MAX, std::u64::MAX);
info!("threads: {} txs: {}", num_threads, total_num_transactions);
let same_payer = matches.is_present("same_payer");
@@ -224,13 +218,8 @@ fn main() {
let blockstore = Arc::new(
Blockstore::open(&ledger_path).expect("Expected to be able to open database ledger"),
);
let leader_schedule_cache = Arc::new(LeaderScheduleCache::new_from_bank(&bank));
let (exit, poh_recorder, poh_service, signal_receiver) = create_test_recorder(
&bank,
&blockstore,
None,
Some(leader_schedule_cache.clone()),
);
let (exit, poh_recorder, poh_service, signal_receiver) =
create_test_recorder(&bank, &blockstore, None);
let cluster_info = ClusterInfo::new(
Node::new_localhost().info,
Arc::new(Keypair::new()),
@@ -340,17 +329,9 @@ fn main() {
bank = bank_forks.working_bank();
insert_time.stop();
// set cost tracker limits to MAX so it will not filter out TXs
bank.write_cost_tracker().unwrap().set_limits(
std::u64::MAX,
std::u64::MAX,
std::u64::MAX,
);
poh_recorder.lock().unwrap().set_bank(&bank);
assert!(poh_recorder.lock().unwrap().bank().is_some());
if bank.slot() > 32 {
leader_schedule_cache.set_root(&bank);
bank_forks.set_root(root, &AbsRequestSender::default(), None);
root += 1;
}

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-banks-client"
version = "1.11.0"
version = "1.9.5"
description = "Solana banks client"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@@ -10,19 +10,19 @@ documentation = "https://docs.rs/solana-banks-client"
edition = "2021"
[dependencies]
borsh = "0.9.3"
borsh = "0.9.1"
futures = "0.3"
solana-banks-interface = { path = "../banks-interface", version = "=1.11.0" }
solana-program = { path = "../sdk/program", version = "=1.11.0" }
solana-sdk = { path = "../sdk", version = "=1.11.0" }
solana-banks-interface = { path = "../banks-interface", version = "=1.9.5" }
solana-program = { path = "../sdk/program", version = "=1.9.5" }
solana-sdk = { path = "../sdk", version = "=1.9.5" }
tarpc = { version = "0.27.2", features = ["full"] }
thiserror = "1.0"
tokio = { version = "1", features = ["full"] }
tokio-serde = { version = "0.8", features = ["bincode"] }
[dev-dependencies]
solana-banks-server = { path = "../banks-server", version = "=1.11.0" }
solana-runtime = { path = "../runtime", version = "=1.11.0" }
solana-runtime = { path = "../runtime", version = "=1.9.5" }
solana-banks-server = { path = "../banks-server", version = "=1.9.5" }
[lib]
crate-type = ["lib"]

View File

@@ -1,8 +1,5 @@
use {
solana_sdk::{
transaction::TransactionError, transaction_context::TransactionReturnData,
transport::TransportError,
},
solana_sdk::{transaction::TransactionError, transport::TransportError},
std::io,
tarpc::client::RpcError,
thiserror::Error,
@@ -28,7 +25,6 @@ pub enum BanksClientError {
err: TransactionError,
logs: Vec<String>,
units_consumed: u64,
return_data: Option<TransactionReturnData>,
},
}

View File

@@ -5,11 +5,9 @@
//! but they are undocumented, may change over time, and are generally more
//! cumbersome to use.
pub use {
crate::error::BanksClientError,
solana_banks_interface::{BanksClient as TarpcClient, TransactionStatus},
};
pub use solana_banks_interface::{BanksClient as TarpcClient, TransactionStatus};
use {
crate::error::BanksClientError,
borsh::BorshDeserialize,
futures::{future::join_all, Future, FutureExt, TryFutureExt},
solana_banks_interface::{BanksRequest, BanksResponse, BanksTransactionResultWithSimulation},
@@ -23,7 +21,9 @@ use {
message::Message,
signature::Signature,
transaction::{self, Transaction},
transport,
},
std::io,
tarpc::{
client::{self, NewClient, RequestDispatch},
context::{self, Context},
@@ -60,9 +60,10 @@ impl BanksClient {
&mut self,
ctx: Context,
transaction: Transaction,
) -> impl Future<Output = Result<(), BanksClientError>> + '_ {
) -> impl Future<Output = io::Result<()>> + '_ {
self.inner
.send_transaction_with_context(ctx, transaction)
.map_err(BanksClientError::from) // Remove this when return Err type updated to BanksClientError
.map_err(Into::into)
}
@@ -74,10 +75,11 @@ impl BanksClient {
&mut self,
ctx: Context,
commitment: CommitmentLevel,
) -> impl Future<Output = Result<(FeeCalculator, Hash, u64), BanksClientError>> + '_ {
) -> impl Future<Output = io::Result<(FeeCalculator, Hash, u64)>> + '_ {
#[allow(deprecated)]
self.inner
.get_fees_with_commitment_and_context(ctx, commitment)
.map_err(BanksClientError::from) // Remove this when return Err type updated to BanksClientError
.map_err(Into::into)
}
@@ -85,9 +87,10 @@ impl BanksClient {
&mut self,
ctx: Context,
signature: Signature,
) -> impl Future<Output = Result<Option<TransactionStatus>, BanksClientError>> + '_ {
) -> impl Future<Output = io::Result<Option<TransactionStatus>>> + '_ {
self.inner
.get_transaction_status_with_context(ctx, signature)
.map_err(BanksClientError::from) // Remove this when return Err type updated to BanksClientError
.map_err(Into::into)
}
@@ -95,9 +98,10 @@ impl BanksClient {
&mut self,
ctx: Context,
commitment: CommitmentLevel,
) -> impl Future<Output = Result<Slot, BanksClientError>> + '_ {
) -> impl Future<Output = io::Result<Slot>> + '_ {
self.inner
.get_slot_with_context(ctx, commitment)
.map_err(BanksClientError::from) // Remove this when return Err type updated to BanksClientError
.map_err(Into::into)
}
@@ -105,9 +109,10 @@ impl BanksClient {
&mut self,
ctx: Context,
commitment: CommitmentLevel,
) -> impl Future<Output = Result<Slot, BanksClientError>> + '_ {
) -> impl Future<Output = io::Result<Slot>> + '_ {
self.inner
.get_block_height_with_context(ctx, commitment)
.map_err(BanksClientError::from) // Remove this when return Err type updated to BanksClientError
.map_err(Into::into)
}
@@ -116,9 +121,10 @@ impl BanksClient {
ctx: Context,
transaction: Transaction,
commitment: CommitmentLevel,
) -> impl Future<Output = Result<Option<transaction::Result<()>>, BanksClientError>> + '_ {
) -> impl Future<Output = io::Result<Option<transaction::Result<()>>>> + '_ {
self.inner
.process_transaction_with_commitment_and_context(ctx, transaction, commitment)
.map_err(BanksClientError::from) // Remove this when return Err type updated to BanksClientError
.map_err(Into::into)
}
@@ -143,9 +149,10 @@ impl BanksClient {
ctx: Context,
address: Pubkey,
commitment: CommitmentLevel,
) -> impl Future<Output = Result<Option<Account>, BanksClientError>> + '_ {
) -> impl Future<Output = io::Result<Option<Account>>> + '_ {
self.inner
.get_account_with_commitment_and_context(ctx, address, commitment)
.map_err(BanksClientError::from) // Remove this when return Err type updated to BanksClientError
.map_err(Into::into)
}
@@ -155,7 +162,7 @@ impl BanksClient {
pub fn send_transaction(
&mut self,
transaction: Transaction,
) -> impl Future<Output = Result<(), BanksClientError>> + '_ {
) -> impl Future<Output = io::Result<()>> + '_ {
self.send_transaction_with_context(context::current(), transaction)
}
@@ -168,25 +175,27 @@ impl BanksClient {
)]
pub fn get_fees(
&mut self,
) -> impl Future<Output = Result<(FeeCalculator, Hash, u64), BanksClientError>> + '_ {
) -> impl Future<Output = io::Result<(FeeCalculator, Hash, u64)>> + '_ {
#[allow(deprecated)]
self.get_fees_with_commitment_and_context(context::current(), CommitmentLevel::default())
}
/// Return the cluster Sysvar
pub fn get_sysvar<T: Sysvar>(
&mut self,
) -> impl Future<Output = Result<T, BanksClientError>> + '_ {
pub fn get_sysvar<T: Sysvar>(&mut self) -> impl Future<Output = io::Result<T>> + '_ {
self.get_account(T::id()).map(|result| {
let sysvar = result?.ok_or(BanksClientError::ClientError("Sysvar not present"))?;
from_account::<T, _>(&sysvar).ok_or(BanksClientError::ClientError(
"Failed to deserialize sysvar",
))
let sysvar = result?
.ok_or(BanksClientError::ClientError("Sysvar not present"))
.map_err(io::Error::from)?; // Remove this map when return Err type updated to BanksClientError
from_account::<T, _>(&sysvar)
.ok_or(BanksClientError::ClientError(
"Failed to deserialize sysvar",
))
.map_err(Into::into) // Remove this when return Err type updated to BanksClientError
})
}
/// Return the cluster rent
pub fn get_rent(&mut self) -> impl Future<Output = Result<Rent, BanksClientError>> + '_ {
pub fn get_rent(&mut self) -> impl Future<Output = io::Result<Rent>> + '_ {
self.get_sysvar::<Rent>()
}
@@ -194,9 +203,7 @@ impl BanksClient {
/// transactions with a blockhash that has not yet expired. Use the `get_fees`
/// method to get both a blockhash and the blockhash's last valid slot.
#[deprecated(since = "1.9.0", note = "Please use `get_latest_blockhash` instead")]
pub fn get_recent_blockhash(
&mut self,
) -> impl Future<Output = Result<Hash, BanksClientError>> + '_ {
pub fn get_recent_blockhash(&mut self) -> impl Future<Output = io::Result<Hash>> + '_ {
#[allow(deprecated)]
self.get_fees().map(|result| Ok(result?.1))
}
@@ -207,7 +214,7 @@ impl BanksClient {
&mut self,
transaction: Transaction,
commitment: CommitmentLevel,
) -> impl Future<Output = Result<(), BanksClientError>> + '_ {
) -> impl Future<Output = transport::Result<()>> + '_ {
let mut ctx = context::current();
ctx.deadline += Duration::from_secs(50);
self.process_transaction_with_commitment_and_context(ctx, transaction, commitment)
@@ -217,6 +224,7 @@ impl BanksClient {
)),
Some(transaction_result) => Ok(transaction_result?),
})
.map_err(Into::into) // Remove this when return Err type updated to BanksClientError
}
/// Send a transaction and return any preflight (sanitization or simulation) errors, or return
@@ -247,7 +255,6 @@ impl BanksClient {
err,
logs: simulation_details.logs,
units_consumed: simulation_details.units_consumed,
return_data: simulation_details.return_data,
}),
BanksTransactionResultWithSimulation {
result: Some(result),
@@ -272,7 +279,7 @@ impl BanksClient {
pub fn process_transaction(
&mut self,
transaction: Transaction,
) -> impl Future<Output = Result<(), BanksClientError>> + '_ {
) -> impl Future<Output = transport::Result<()>> + '_ {
self.process_transaction_with_commitment(transaction, CommitmentLevel::default())
}
@@ -280,7 +287,7 @@ impl BanksClient {
&mut self,
transactions: Vec<Transaction>,
commitment: CommitmentLevel,
) -> Result<(), BanksClientError> {
) -> transport::Result<()> {
let mut clients: Vec<_> = transactions.iter().map(|_| self.clone()).collect();
let futures = clients
.iter_mut()
@@ -296,21 +303,19 @@ impl BanksClient {
pub fn process_transactions(
&mut self,
transactions: Vec<Transaction>,
) -> impl Future<Output = Result<(), BanksClientError>> + '_ {
) -> impl Future<Output = transport::Result<()>> + '_ {
self.process_transactions_with_commitment(transactions, CommitmentLevel::default())
}
/// Return the most recent rooted slot. All transactions at or below this slot
/// are said to be finalized. The cluster will not fork to a higher slot.
pub fn get_root_slot(&mut self) -> impl Future<Output = Result<Slot, BanksClientError>> + '_ {
pub fn get_root_slot(&mut self) -> impl Future<Output = io::Result<Slot>> + '_ {
self.get_slot_with_context(context::current(), CommitmentLevel::default())
}
/// Return the most recent rooted block height. All transactions at or below this height
/// are said to be finalized. The cluster will not fork to a higher block height.
pub fn get_root_block_height(
&mut self,
) -> impl Future<Output = Result<Slot, BanksClientError>> + '_ {
pub fn get_root_block_height(&mut self) -> impl Future<Output = io::Result<Slot>> + '_ {
self.get_block_height_with_context(context::current(), CommitmentLevel::default())
}
@@ -320,7 +325,7 @@ impl BanksClient {
&mut self,
address: Pubkey,
commitment: CommitmentLevel,
) -> impl Future<Output = Result<Option<Account>, BanksClientError>> + '_ {
) -> impl Future<Output = io::Result<Option<Account>>> + '_ {
self.get_account_with_commitment_and_context(context::current(), address, commitment)
}
@@ -329,7 +334,7 @@ impl BanksClient {
pub fn get_account(
&mut self,
address: Pubkey,
) -> impl Future<Output = Result<Option<Account>, BanksClientError>> + '_ {
) -> impl Future<Output = io::Result<Option<Account>>> + '_ {
self.get_account_with_commitment(address, CommitmentLevel::default())
}
@@ -338,11 +343,14 @@ impl BanksClient {
pub fn get_packed_account_data<T: Pack>(
&mut self,
address: Pubkey,
) -> impl Future<Output = Result<T, BanksClientError>> + '_ {
) -> impl Future<Output = io::Result<T>> + '_ {
self.get_account(address).map(|result| {
let account = result?.ok_or(BanksClientError::ClientError("Account not found"))?;
let account = result?
.ok_or(BanksClientError::ClientError("Account not found"))
.map_err(io::Error::from)?; // Remove this map when return Err type updated to BanksClientError
T::unpack_from_slice(&account.data)
.map_err(|_| BanksClientError::ClientError("Failed to deserialize account"))
.map_err(Into::into) // Remove this when return Err type updated to BanksClientError
})
}
@@ -351,7 +359,7 @@ impl BanksClient {
pub fn get_account_data_with_borsh<T: BorshDeserialize>(
&mut self,
address: Pubkey,
) -> impl Future<Output = Result<T, BanksClientError>> + '_ {
) -> impl Future<Output = io::Result<T>> + '_ {
self.get_account(address).map(|result| {
let account = result?.ok_or(BanksClientError::ClientError("Account not found"))?;
T::try_from_slice(&account.data).map_err(Into::into)
@@ -364,17 +372,14 @@ impl BanksClient {
&mut self,
address: Pubkey,
commitment: CommitmentLevel,
) -> impl Future<Output = Result<u64, BanksClientError>> + '_ {
) -> impl Future<Output = io::Result<u64>> + '_ {
self.get_account_with_commitment_and_context(context::current(), address, commitment)
.map(|result| Ok(result?.map(|x| x.lamports).unwrap_or(0)))
}
/// Return the balance in lamports of an account at the given address at the time
/// of the most recent root slot.
pub fn get_balance(
&mut self,
address: Pubkey,
) -> impl Future<Output = Result<u64, BanksClientError>> + '_ {
pub fn get_balance(&mut self, address: Pubkey) -> impl Future<Output = io::Result<u64>> + '_ {
self.get_balance_with_commitment(address, CommitmentLevel::default())
}
@@ -386,7 +391,7 @@ impl BanksClient {
pub fn get_transaction_status(
&mut self,
signature: Signature,
) -> impl Future<Output = Result<Option<TransactionStatus>, BanksClientError>> + '_ {
) -> impl Future<Output = io::Result<Option<TransactionStatus>>> + '_ {
self.get_transaction_status_with_context(context::current(), signature)
}
@@ -394,7 +399,7 @@ impl BanksClient {
pub async fn get_transaction_statuses(
&mut self,
signatures: Vec<Signature>,
) -> Result<Vec<Option<TransactionStatus>>, BanksClientError> {
) -> io::Result<Vec<Option<TransactionStatus>>> {
// tarpc futures oddly hold a mutable reference back to the client so clone the client upfront
let mut clients_and_signatures: Vec<_> = signatures
.into_iter()
@@ -411,9 +416,7 @@ impl BanksClient {
statuses.into_iter().collect()
}
pub fn get_latest_blockhash(
&mut self,
) -> impl Future<Output = Result<Hash, BanksClientError>> + '_ {
pub fn get_latest_blockhash(&mut self) -> impl Future<Output = io::Result<Hash>> + '_ {
self.get_latest_blockhash_with_commitment(CommitmentLevel::default())
.map(|result| {
result?
@@ -426,7 +429,7 @@ impl BanksClient {
pub fn get_latest_blockhash_with_commitment(
&mut self,
commitment: CommitmentLevel,
) -> impl Future<Output = Result<Option<(Hash, u64)>, BanksClientError>> + '_ {
) -> impl Future<Output = io::Result<Option<(Hash, u64)>>> + '_ {
self.get_latest_blockhash_with_commitment_and_context(context::current(), commitment)
}
@@ -434,9 +437,10 @@ impl BanksClient {
&mut self,
ctx: Context,
commitment: CommitmentLevel,
) -> impl Future<Output = Result<Option<(Hash, u64)>, BanksClientError>> + '_ {
) -> impl Future<Output = io::Result<Option<(Hash, u64)>>> + '_ {
self.inner
.get_latest_blockhash_with_commitment_and_context(ctx, commitment)
.map_err(BanksClientError::from) // Remove this when return Err type updated to BanksClientError
.map_err(Into::into)
}
@@ -445,14 +449,15 @@ impl BanksClient {
ctx: Context,
commitment: CommitmentLevel,
message: Message,
) -> impl Future<Output = Result<Option<u64>, BanksClientError>> + '_ {
) -> impl Future<Output = io::Result<Option<u64>>> + '_ {
self.inner
.get_fee_for_message_with_commitment_and_context(ctx, commitment, message)
.map_err(BanksClientError::from) // Remove this when return Err type updated to BanksClientError
.map_err(Into::into)
}
}
pub async fn start_client<C>(transport: C) -> Result<BanksClient, BanksClientError>
pub async fn start_client<C>(transport: C) -> io::Result<BanksClient>
where
C: Transport<ClientMessage<BanksRequest>, Response<BanksResponse>> + Send + 'static,
{
@@ -461,7 +466,7 @@ where
})
}
pub async fn start_tcp_client<T: ToSocketAddrs>(addr: T) -> Result<BanksClient, BanksClientError> {
pub async fn start_tcp_client<T: ToSocketAddrs>(addr: T) -> io::Result<BanksClient> {
let transport = tcp::connect(addr, Bincode::default).await?;
Ok(BanksClient {
inner: TarpcClient::new(client::Config::default(), transport).spawn(),

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-banks-interface"
version = "1.11.0"
version = "1.9.5"
description = "Solana banks RPC interface"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@@ -10,8 +10,8 @@ documentation = "https://docs.rs/solana-banks-interface"
edition = "2021"
[dependencies]
serde = { version = "1.0.136", features = ["derive"] }
solana-sdk = { path = "../sdk", version = "=1.11.0" }
serde = { version = "1.0.130", features = ["derive"] }
solana-sdk = { path = "../sdk", version = "=1.9.5" }
tarpc = { version = "0.27.2", features = ["full"] }
[lib]

View File

@@ -12,7 +12,6 @@ use {
pubkey::Pubkey,
signature::Signature,
transaction::{self, Transaction, TransactionError},
transaction_context::TransactionReturnData,
},
};
@@ -36,7 +35,6 @@ pub struct TransactionStatus {
pub struct TransactionSimulationDetails {
pub logs: Vec<String>,
pub units_consumed: u64,
pub return_data: Option<TransactionReturnData>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-banks-server"
version = "1.11.0"
version = "1.9.5"
description = "Solana banks server"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@@ -11,12 +11,11 @@ edition = "2021"
[dependencies]
bincode = "1.3.3"
crossbeam-channel = "0.5"
futures = "0.3"
solana-banks-interface = { path = "../banks-interface", version = "=1.11.0" }
solana-runtime = { path = "../runtime", version = "=1.11.0" }
solana-sdk = { path = "../sdk", version = "=1.11.0" }
solana-send-transaction-service = { path = "../send-transaction-service", version = "=1.11.0" }
solana-banks-interface = { path = "../banks-interface", version = "=1.9.5" }
solana-runtime = { path = "../runtime", version = "=1.9.5" }
solana-sdk = { path = "../sdk", version = "=1.9.5" }
solana-send-transaction-service = { path = "../send-transaction-service", version = "=1.9.5" }
tarpc = { version = "0.27.2", features = ["full"] }
tokio = { version = "1", features = ["full"] }
tokio-serde = { version = "0.8", features = ["bincode"] }

View File

@@ -1,6 +1,5 @@
use {
bincode::{deserialize, serialize},
crossbeam_channel::{unbounded, Receiver, Sender},
futures::{future, prelude::stream::StreamExt},
solana_banks_interface::{
Banks, BanksRequest, BanksResponse, BanksTransactionResultWithSimulation,
@@ -24,14 +23,17 @@ use {
transaction::{self, SanitizedTransaction, Transaction},
},
solana_send_transaction_service::{
send_transaction_service::{SendTransactionService, TransactionInfo, DEFAULT_TPU_USE_QUIC},
send_transaction_service::{SendTransactionService, TransactionInfo},
tpu_info::NullTpuInfo,
},
std::{
convert::TryFrom,
io,
net::{Ipv4Addr, SocketAddr},
sync::{Arc, RwLock},
sync::{
mpsc::{channel, Receiver, Sender},
Arc, RwLock,
},
thread::Builder,
time::Duration,
},
@@ -94,7 +96,7 @@ impl BanksServer {
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
poll_signature_status_sleep_duration: Duration,
) -> Self {
let (transaction_sender, transaction_receiver) = unbounded();
let (transaction_sender, transaction_receiver) = channel();
let bank = bank_forks.read().unwrap().working_bank();
let slot = bank.slot();
{
@@ -266,7 +268,6 @@ impl Banks for BanksServer {
logs,
post_simulation_accounts: _,
units_consumed,
return_data,
} = self
.bank(commitment)
.simulate_transaction_unchecked(sanitized_transaction)
@@ -276,7 +277,6 @@ impl Banks for BanksServer {
simulation_details: Some(TransactionSimulationDetails {
logs,
units_consumed,
return_data,
}),
};
}
@@ -392,7 +392,7 @@ pub async fn start_tcp_server(
// serve is generated by the service attribute. It takes as input any type implementing
// the generated Banks trait.
.map(move |chan| {
let (sender, receiver) = unbounded();
let (sender, receiver) = channel();
SendTransactionService::new::<NullTpuInfo>(
tpu_addr,
@@ -401,7 +401,6 @@ pub async fn start_tcp_server(
receiver,
5_000,
0,
DEFAULT_TPU_USE_QUIC,
);
let server = BanksServer::new(

View File

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

View File

@@ -1,7 +1,6 @@
#![allow(clippy::integer_arithmetic)]
use {
clap::{crate_description, crate_name, Arg, Command},
crossbeam_channel::unbounded,
clap::{crate_description, crate_name, App, Arg},
solana_streamer::{
packet::{Packet, PacketBatch, PacketBatchRecycler, PACKET_DATA_SIZE},
streamer::{receiver, PacketBatchReceiver},
@@ -11,6 +10,7 @@ use {
net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket},
sync::{
atomic::{AtomicBool, AtomicUsize, Ordering},
mpsc::channel,
Arc,
},
thread::{sleep, spawn, JoinHandle, Result},
@@ -57,32 +57,23 @@ fn sink(exit: Arc<AtomicBool>, rvs: Arc<AtomicUsize>, r: PacketBatchReceiver) ->
fn main() -> Result<()> {
let mut num_sockets = 1usize;
let matches = Command::new(crate_name!())
let matches = App::new(crate_name!())
.about(crate_description!())
.version(solana_version::version!())
.arg(
Arg::new("num-recv-sockets")
Arg::with_name("num-recv-sockets")
.long("num-recv-sockets")
.value_name("NUM")
.takes_value(true)
.help("Use NUM receive sockets"),
)
.arg(
Arg::new("num-producers")
.long("num-producers")
.value_name("NUM")
.takes_value(true)
.help("Use this many producer threads."),
)
.get_matches();
if let Some(n) = matches.value_of("num-recv-sockets") {
num_sockets = max(num_sockets, n.to_string().parse().expect("integer"));
}
let num_producers: u64 = matches.value_of_t("num_producers").unwrap_or(4);
let port = 0;
let mut port = 0;
let ip_addr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0));
let mut addr = SocketAddr::new(ip_addr, 0);
@@ -91,17 +82,14 @@ fn main() -> Result<()> {
let mut read_channels = Vec::new();
let mut read_threads = Vec::new();
let recycler = PacketBatchRecycler::default();
let (_port, read_sockets) = solana_net_utils::multi_bind_in_range(
ip_addr,
(port, port + num_sockets as u16),
num_sockets,
)
.unwrap();
for read in read_sockets {
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();
addr = read.local_addr().unwrap();
let (s_reader, r_reader) = unbounded();
port = addr.port();
let (s_reader, r_reader) = channel();
read_channels.push(r_reader);
read_threads.push(receiver(
Arc::new(read),
@@ -114,10 +102,9 @@ fn main() -> Result<()> {
));
}
let producer_threads: Vec<_> = (0..num_producers)
.into_iter()
.map(|_| producer(&addr, exit.clone()))
.collect();
let t_producer1 = producer(&addr, exit.clone());
let t_producer2 = producer(&addr, exit.clone());
let t_producer3 = producer(&addr, exit.clone());
let rvs = Arc::new(AtomicUsize::new(0));
let sink_threads: Vec<_> = read_channels
@@ -137,9 +124,9 @@ fn main() -> Result<()> {
for t_reader in read_threads {
t_reader.join()?;
}
for t_producer in producer_threads {
t_producer.join()?;
}
t_producer1.join()?;
t_producer2.join()?;
t_producer3.join()?;
for t_sink in sink_threads {
t_sink.join()?;
}

View File

@@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2021"
name = "solana-bench-tps"
version = "1.11.0"
version = "1.9.5"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@@ -10,33 +10,27 @@ publish = false
[dependencies]
clap = "2.33.1"
crossbeam-channel = "0.5"
log = "0.4.14"
rayon = "1.5.1"
serde_json = "1.0.79"
serde_yaml = "0.8.23"
solana-clap-utils = { path = "../clap-utils", version = "=1.11.0" }
solana-cli-config = { path = "../cli-config", version = "=1.11.0" }
solana-client = { path = "../client", version = "=1.11.0" }
solana-core = { path = "../core", version = "=1.11.0" }
solana-faucet = { path = "../faucet", version = "=1.11.0" }
solana-genesis = { path = "../genesis", version = "=1.11.0" }
solana-gossip = { path = "../gossip", version = "=1.11.0" }
solana-logger = { path = "../logger", version = "=1.11.0" }
solana-measure = { path = "../measure", version = "=1.11.0" }
solana-metrics = { path = "../metrics", version = "=1.11.0" }
solana-net-utils = { path = "../net-utils", version = "=1.11.0" }
solana-rpc = { path = "../rpc", version = "=1.11.0" }
solana-runtime = { path = "../runtime", version = "=1.11.0" }
solana-sdk = { path = "../sdk", version = "=1.11.0" }
solana-streamer = { path = "../streamer", version = "=1.11.0" }
solana-version = { path = "../version", version = "=1.11.0" }
thiserror = "1.0"
serde_json = "1.0.72"
serde_yaml = "0.8.21"
solana-core = { path = "../core", version = "=1.9.5" }
solana-genesis = { path = "../genesis", version = "=1.9.5" }
solana-client = { path = "../client", version = "=1.9.5" }
solana-faucet = { path = "../faucet", version = "=1.9.5" }
solana-gossip = { path = "../gossip", version = "=1.9.5" }
solana-logger = { path = "../logger", version = "=1.9.5" }
solana-metrics = { path = "../metrics", version = "=1.9.5" }
solana-measure = { path = "../measure", version = "=1.9.5" }
solana-net-utils = { path = "../net-utils", version = "=1.9.5" }
solana-runtime = { path = "../runtime", version = "=1.9.5" }
solana-sdk = { path = "../sdk", version = "=1.9.5" }
solana-streamer = { path = "../streamer", version = "=1.9.5" }
solana-version = { path = "../version", version = "=1.9.5" }
[dev-dependencies]
serial_test = "0.6.0"
solana-local-cluster = { path = "../local-cluster", version = "=1.11.0" }
solana-test-validator = { path = "../test-validator", version = "=1.11.0" }
serial_test = "0.5.1"
solana-local-cluster = { path = "../local-cluster", version = "=1.9.5" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -1,21 +1,19 @@
use {
crate::{
bench_tps_client::*,
cli::Config,
perf_utils::{sample_txs, SampleStats},
},
crate::cli::Config,
log::*,
rayon::prelude::*,
solana_client::perf_utils::{sample_txs, SampleStats},
solana_core::gen_keys::GenKeys,
solana_faucet::faucet::request_airdrop_transaction,
solana_measure::measure::Measure,
solana_metrics::{self, datapoint_info},
solana_sdk::{
client::Client,
clock::{DEFAULT_MS_PER_SLOT, DEFAULT_S_PER_SLOT, MAX_PROCESSING_AGE},
commitment_config::CommitmentConfig,
hash::Hash,
instruction::{AccountMeta, Instruction},
message::Message,
native_token::Sol,
pubkey::Pubkey,
signature::{Keypair, Signer},
system_instruction, system_transaction,
@@ -24,6 +22,7 @@ use {
},
std::{
collections::{HashSet, VecDeque},
net::SocketAddr,
process::exit,
sync::{
atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering},
@@ -39,9 +38,16 @@ const MAX_TX_QUEUE_AGE: u64 = (MAX_PROCESSING_AGE as f64 * DEFAULT_S_PER_SLOT) a
pub const MAX_SPENDS_PER_TX: u64 = 4;
#[derive(Debug)]
pub enum BenchTpsError {
AirdropFailure,
}
pub type Result<T> = std::result::Result<T, BenchTpsError>;
pub type SharedTransactions = Arc<RwLock<VecDeque<Vec<(Transaction, u64)>>>>;
fn get_latest_blockhash<T: BenchTpsClient>(client: &T) -> Hash {
fn get_latest_blockhash<T: Client>(client: &T) -> Hash {
loop {
match client.get_latest_blockhash_with_commitment(CommitmentConfig::processed()) {
Ok((blockhash, _)) => return blockhash,
@@ -55,7 +61,7 @@ fn get_latest_blockhash<T: BenchTpsClient>(client: &T) -> Hash {
fn wait_for_target_slots_per_epoch<T>(target_slots_per_epoch: u64, client: &Arc<T>)
where
T: 'static + BenchTpsClient + Send + Sync,
T: 'static + Client + Send + Sync,
{
if target_slots_per_epoch != 0 {
info!(
@@ -85,7 +91,7 @@ fn create_sampler_thread<T>(
maxes: &Arc<RwLock<Vec<(String, SampleStats)>>>,
) -> JoinHandle<()>
where
T: 'static + BenchTpsClient + Send + Sync,
T: 'static + Client + Send + Sync,
{
info!("Sampling TPS every {} second...", sample_period);
let exit_signal = exit_signal.clone();
@@ -104,7 +110,7 @@ fn generate_chunked_transfers(
shared_txs: &SharedTransactions,
shared_tx_active_thread_count: Arc<AtomicIsize>,
source_keypair_chunks: Vec<Vec<&Keypair>>,
dest_keypair_chunks: &mut [VecDeque<&Keypair>],
dest_keypair_chunks: &mut Vec<VecDeque<&Keypair>>,
threads: usize,
duration: Duration,
sustained: bool,
@@ -163,7 +169,7 @@ fn create_sender_threads<T>(
shared_tx_active_thread_count: &Arc<AtomicIsize>,
) -> Vec<JoinHandle<()>>
where
T: 'static + BenchTpsClient + Send + Sync,
T: 'static + Client + Send + Sync,
{
(0..threads)
.map(|_| {
@@ -191,7 +197,7 @@ where
pub fn do_bench_tps<T>(client: Arc<T>, config: Config, gen_keypairs: Vec<Keypair>) -> u64
where
T: 'static + BenchTpsClient + Send + Sync,
T: 'static + Client + Send + Sync,
{
let Config {
id,
@@ -385,7 +391,7 @@ fn generate_txs(
}
}
fn get_new_latest_blockhash<T: BenchTpsClient>(client: &Arc<T>, blockhash: &Hash) -> Option<Hash> {
fn get_new_latest_blockhash<T: Client>(client: &Arc<T>, blockhash: &Hash) -> Option<Hash> {
let start = Instant::now();
while start.elapsed().as_secs() < 5 {
if let Ok(new_blockhash) = client.get_latest_blockhash() {
@@ -401,7 +407,7 @@ fn get_new_latest_blockhash<T: BenchTpsClient>(client: &Arc<T>, blockhash: &Hash
None
}
fn poll_blockhash<T: BenchTpsClient>(
fn poll_blockhash<T: Client>(
exit_signal: &Arc<AtomicBool>,
blockhash: &Arc<RwLock<Hash>>,
client: &Arc<T>,
@@ -443,7 +449,7 @@ fn poll_blockhash<T: BenchTpsClient>(
}
}
fn do_tx_transfers<T: BenchTpsClient>(
fn do_tx_transfers<T: Client>(
exit_signal: &Arc<AtomicBool>,
shared_txs: &SharedTransactions,
shared_tx_thread_count: &Arc<AtomicIsize>,
@@ -461,11 +467,14 @@ fn do_tx_transfers<T: BenchTpsClient>(
};
if let Some(txs0) = txs {
shared_tx_thread_count.fetch_add(1, Ordering::Relaxed);
info!("Transferring 1 unit {} times...", txs0.len());
info!(
"Transferring 1 unit {} times... to {}",
txs0.len(),
client.as_ref().tpu_addr(),
);
let tx_len = txs0.len();
let transfer_start = Instant::now();
let mut old_transactions = false;
let mut transactions = Vec::<_>::new();
for tx in txs0 {
let now = timestamp();
// Transactions that are too old will be rejected by the cluster Don't bother
@@ -474,13 +483,10 @@ fn do_tx_transfers<T: BenchTpsClient>(
old_transactions = true;
continue;
}
transactions.push(tx.0);
client
.async_send_transaction(tx.0)
.expect("async_send_transaction in do_tx_transfers");
}
if let Err(error) = client.send_batch(transactions) {
warn!("send_batch_sync in do_tx_transfers failed: {}", error);
}
if old_transactions {
let mut shared_txs_wl = shared_txs.write().expect("write lock in do_tx_transfers");
shared_txs_wl.clear();
@@ -504,11 +510,7 @@ fn do_tx_transfers<T: BenchTpsClient>(
}
}
fn verify_funding_transfer<T: BenchTpsClient>(
client: &Arc<T>,
tx: &Transaction,
amount: u64,
) -> bool {
fn verify_funding_transfer<T: Client>(client: &Arc<T>, tx: &Transaction, amount: u64) -> bool {
for a in &tx.message().account_keys[1..] {
match client.get_balance_with_commitment(a, CommitmentConfig::processed()) {
Ok(balance) => return balance >= amount,
@@ -519,7 +521,7 @@ fn verify_funding_transfer<T: BenchTpsClient>(
}
trait FundingTransactions<'a> {
fn fund<T: 'static + BenchTpsClient + Send + Sync>(
fn fund<T: 'static + Client + Send + Sync>(
&mut self,
client: &Arc<T>,
to_fund: &[(&'a Keypair, Vec<(Pubkey, u64)>)],
@@ -527,16 +529,12 @@ trait FundingTransactions<'a> {
);
fn make(&mut self, to_fund: &[(&'a Keypair, Vec<(Pubkey, u64)>)]);
fn sign(&mut self, blockhash: Hash);
fn send<T: BenchTpsClient>(&self, client: &Arc<T>);
fn verify<T: 'static + BenchTpsClient + Send + Sync>(
&mut self,
client: &Arc<T>,
to_lamports: u64,
);
fn send<T: Client>(&self, client: &Arc<T>);
fn verify<T: 'static + Client + Send + Sync>(&mut self, client: &Arc<T>, to_lamports: u64);
}
impl<'a> FundingTransactions<'a> for Vec<(&'a Keypair, Transaction)> {
fn fund<T: 'static + BenchTpsClient + Send + Sync>(
fn fund<T: 'static + Client + Send + Sync>(
&mut self,
client: &Arc<T>,
to_fund: &[(&'a Keypair, Vec<(Pubkey, u64)>)],
@@ -605,20 +603,16 @@ impl<'a> FundingTransactions<'a> for Vec<(&'a Keypair, Transaction)> {
debug!("sign {} txs: {}us", self.len(), sign_txs.as_us());
}
fn send<T: BenchTpsClient>(&self, client: &Arc<T>) {
fn send<T: Client>(&self, client: &Arc<T>) {
let mut send_txs = Measure::start("send_txs");
self.iter().for_each(|(_, tx)| {
client.send_transaction(tx.clone()).expect("transfer");
client.async_send_transaction(tx.clone()).expect("transfer");
});
send_txs.stop();
debug!("send {} txs: {}us", self.len(), send_txs.as_us());
}
fn verify<T: 'static + BenchTpsClient + Send + Sync>(
&mut self,
client: &Arc<T>,
to_lamports: u64,
) {
fn verify<T: 'static + Client + Send + Sync>(&mut self, client: &Arc<T>, to_lamports: u64) {
let starting_txs = self.len();
let verified_txs = Arc::new(AtomicUsize::new(0));
let too_many_failures = Arc::new(AtomicBool::new(false));
@@ -693,7 +687,7 @@ impl<'a> FundingTransactions<'a> for Vec<(&'a Keypair, Transaction)> {
/// fund the dests keys by spending all of the source keys into MAX_SPENDS_PER_TX
/// on every iteration. This allows us to replay the transfers because the source is either empty,
/// or full
pub fn fund_keys<T: 'static + BenchTpsClient + Send + Sync>(
pub fn fund_keys<T: 'static + Client + Send + Sync>(
client: Arc<T>,
source: &Keypair,
dests: &[Keypair],
@@ -735,6 +729,75 @@ pub fn fund_keys<T: 'static + BenchTpsClient + Send + Sync>(
}
}
pub fn airdrop_lamports<T: Client>(
client: &T,
faucet_addr: &SocketAddr,
id: &Keypair,
desired_balance: u64,
) -> Result<()> {
let starting_balance = client.get_balance(&id.pubkey()).unwrap_or(0);
metrics_submit_lamport_balance(starting_balance);
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 = get_latest_blockhash(client);
match request_airdrop_transaction(faucet_addr, &id.pubkey(), airdrop_amount, blockhash) {
Ok(transaction) => {
let mut tries = 0;
loop {
tries += 1;
let signature = client.async_send_transaction(transaction.clone()).unwrap();
let result = client.poll_for_signature_confirmation(&signature, 1);
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_with_commitment(&id.pubkey(), CommitmentConfig::processed())
.unwrap_or_else(|e| {
info!("airdrop error {}", e);
starting_balance
});
info!("current balance {}...", current_balance);
metrics_submit_lamport_balance(current_balance);
if current_balance - starting_balance != airdrop_amount {
info!(
"Airdrop failed! {} {} {}",
id.pubkey(),
current_balance,
starting_balance
);
return Err(BenchTpsError::AirdropFailure);
}
}
Ok(())
}
fn compute_and_report_stats(
maxes: &Arc<RwLock<Vec<(String, SampleStats)>>>,
sample_period: u64,
@@ -818,33 +881,15 @@ pub fn generate_keypairs(seed_keypair: &Keypair, count: u64) -> (Vec<Keypair>, u
(rnd.gen_n_keypairs(total_keys), extra)
}
pub fn generate_and_fund_keypairs<T: 'static + BenchTpsClient + Send + Sync>(
pub fn generate_and_fund_keypairs<T: 'static + Client + Send + Sync>(
client: Arc<T>,
faucet_addr: Option<SocketAddr>,
funding_key: &Keypair,
keypair_count: usize,
lamports_per_account: u64,
) -> Result<Vec<Keypair>> {
let rent = client.get_minimum_balance_for_rent_exemption(0)?;
let lamports_per_account = lamports_per_account + rent;
info!("Creating {} keypairs...", keypair_count);
let (mut keypairs, extra) = generate_keypairs(funding_key, keypair_count as u64);
fund_keypairs(client, funding_key, &keypairs, extra, lamports_per_account)?;
// 'generate_keypairs' generates extra keys to be able to have size-aligned funding batches for fund_keys.
keypairs.truncate(keypair_count);
Ok(keypairs)
}
pub fn fund_keypairs<T: 'static + BenchTpsClient + Send + Sync>(
client: Arc<T>,
funding_key: &Keypair,
keypairs: &[Keypair],
extra: u64,
lamports_per_account: u64,
) -> Result<()> {
let rent = client.get_minimum_balance_for_rent_exemption(0)?;
info!("Get lamports...");
// Sample the first keypair, to prevent lamport loss on repeated solana-bench-tps executions
@@ -852,7 +897,7 @@ pub fn fund_keypairs<T: 'static + BenchTpsClient + Send + Sync>(
let first_keypair_balance = client.get_balance(&first_key).unwrap_or(0);
// Sample the last keypair, to check if funding was already completed
let last_key = keypairs[keypairs.len() - 1].pubkey();
let last_key = keypairs[keypair_count - 1].pubkey();
let last_keypair_balance = client.get_balance(&last_key).unwrap_or(0);
// Repeated runs will eat up keypair balances from transaction fees. In order to quickly
@@ -881,35 +926,24 @@ pub fn fund_keypairs<T: 'static + BenchTpsClient + Send + Sync>(
funding_key_balance, max_fee, lamports_per_account, extra, total
);
if funding_key_balance < total + rent {
error!(
"funder has {}, needed {}",
Sol(funding_key_balance),
Sol(total)
);
let latest_blockhash = get_latest_blockhash(client.as_ref());
if client
.request_airdrop_with_blockhash(
&funding_key.pubkey(),
total + rent - funding_key_balance,
&latest_blockhash,
)
.is_err()
{
return Err(BenchTpsError::AirdropFailure);
}
if client.get_balance(&funding_key.pubkey()).unwrap_or(0) < total {
airdrop_lamports(client.as_ref(), &faucet_addr.unwrap(), funding_key, total)?;
}
fund_keys(
client,
funding_key,
keypairs,
&keypairs,
total,
max_fee,
lamports_per_account,
);
}
Ok(())
// 'generate_keypairs' generates extra keys to be able to have size-aligned funding batches for fund_keys.
keypairs.truncate(keypair_count);
Ok(keypairs)
}
#[cfg(test)]
@@ -918,14 +952,14 @@ mod tests {
super::*,
solana_runtime::{bank::Bank, bank_client::BankClient},
solana_sdk::{
fee_calculator::FeeRateGovernor, genesis_config::create_genesis_config,
native_token::sol_to_lamports,
client::SyncClient, fee_calculator::FeeRateGovernor,
genesis_config::create_genesis_config,
},
};
#[test]
fn test_bench_tps_bank_client() {
let (genesis_config, id) = create_genesis_config(sol_to_lamports(10_000.0));
let (genesis_config, id) = create_genesis_config(10_000);
let bank = Bank::new_for_tests(&genesis_config);
let client = Arc::new(BankClient::new(bank));
@@ -938,49 +972,48 @@ mod tests {
let keypair_count = config.tx_count * config.keypair_multiplier;
let keypairs =
generate_and_fund_keypairs(client.clone(), &config.id, keypair_count, 20).unwrap();
generate_and_fund_keypairs(client.clone(), None, &config.id, keypair_count, 20)
.unwrap();
do_bench_tps(client, config, keypairs);
}
#[test]
fn test_bench_tps_fund_keys() {
let (genesis_config, id) = create_genesis_config(sol_to_lamports(10_000.0));
let (genesis_config, id) = create_genesis_config(10_000);
let bank = Bank::new_for_tests(&genesis_config);
let client = Arc::new(BankClient::new(bank));
let keypair_count = 20;
let lamports = 20;
let rent = client.get_minimum_balance_for_rent_exemption(0).unwrap();
let keypairs =
generate_and_fund_keypairs(client.clone(), &id, keypair_count, lamports).unwrap();
generate_and_fund_keypairs(client.clone(), None, &id, keypair_count, lamports).unwrap();
for kp in &keypairs {
assert_eq!(
client
.get_balance_with_commitment(&kp.pubkey(), CommitmentConfig::processed())
.unwrap(),
lamports + rent
lamports
);
}
}
#[test]
fn test_bench_tps_fund_keys_with_fees() {
let (mut genesis_config, id) = create_genesis_config(sol_to_lamports(10_000.0));
let (mut genesis_config, id) = create_genesis_config(10_000);
let fee_rate_governor = FeeRateGovernor::new(11, 0);
genesis_config.fee_rate_governor = fee_rate_governor;
let bank = Bank::new_for_tests(&genesis_config);
let client = Arc::new(BankClient::new(bank));
let keypair_count = 20;
let lamports = 20;
let rent = client.get_minimum_balance_for_rent_exemption(0).unwrap();
let keypairs =
generate_and_fund_keypairs(client.clone(), &id, keypair_count, lamports).unwrap();
generate_and_fund_keypairs(client.clone(), None, &id, keypair_count, lamports).unwrap();
for kp in &keypairs {
assert_eq!(client.get_balance(&kp.pubkey()).unwrap(), lamports + rent);
assert_eq!(client.get_balance(&kp.pubkey()).unwrap(), lamports);
}
}
}

View File

@@ -1,87 +0,0 @@
use {
solana_client::{client_error::ClientError, tpu_client::TpuSenderError},
solana_sdk::{
commitment_config::CommitmentConfig, epoch_info::EpochInfo, hash::Hash, message::Message,
pubkey::Pubkey, signature::Signature, transaction::Transaction, transport::TransportError,
},
thiserror::Error,
};
#[derive(Error, Debug)]
pub enum BenchTpsError {
#[error("Airdrop failure")]
AirdropFailure,
#[error("IO error: {0:?}")]
IoError(#[from] std::io::Error),
#[error("Client error: {0:?}")]
ClientError(#[from] ClientError),
#[error("TpuClient error: {0:?}")]
TpuSenderError(#[from] TpuSenderError),
#[error("Transport error: {0:?}")]
TransportError(#[from] TransportError),
#[error("Custom error: {0}")]
Custom(String),
}
pub(crate) type Result<T> = std::result::Result<T, BenchTpsError>;
pub trait BenchTpsClient {
/// Send a signed transaction without confirmation
fn send_transaction(&self, transaction: Transaction) -> Result<Signature>;
/// Send a batch of signed transactions without confirmation.
fn send_batch(&self, transactions: Vec<Transaction>) -> Result<()>;
/// Get latest blockhash
fn get_latest_blockhash(&self) -> Result<Hash>;
/// Get latest blockhash and its last valid block height, using explicit commitment
fn get_latest_blockhash_with_commitment(
&self,
commitment_config: CommitmentConfig,
) -> Result<(Hash, u64)>;
/// Get transaction count
fn get_transaction_count(&self) -> Result<u64>;
/// Get transaction count, using explicit commitment
fn get_transaction_count_with_commitment(
&self,
commitment_config: CommitmentConfig,
) -> Result<u64>;
/// Get epoch info
fn get_epoch_info(&self) -> Result<EpochInfo>;
/// Get account balance
fn get_balance(&self, pubkey: &Pubkey) -> Result<u64>;
/// Get account balance, using explicit commitment
fn get_balance_with_commitment(
&self,
pubkey: &Pubkey,
commitment_config: CommitmentConfig,
) -> Result<u64>;
/// Calculate the fee for a `Message`
fn get_fee_for_message(&self, message: &Message) -> Result<u64>;
/// Get the rent-exempt minimum for an account
fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> Result<u64>;
/// Return the address of client
fn addr(&self) -> String;
/// Request, submit, and confirm an airdrop transaction
fn request_airdrop_with_blockhash(
&self,
pubkey: &Pubkey,
lamports: u64,
recent_blockhash: &Hash,
) -> Result<Signature>;
}
mod bank_client;
mod rpc_client;
mod thin_client;
mod tpu_client;

View File

@@ -1,85 +0,0 @@
use {
crate::bench_tps_client::{BenchTpsClient, BenchTpsError, Result},
solana_runtime::bank_client::BankClient,
solana_sdk::{
client::{AsyncClient, SyncClient},
commitment_config::CommitmentConfig,
epoch_info::EpochInfo,
hash::Hash,
message::Message,
pubkey::Pubkey,
signature::Signature,
transaction::Transaction,
},
};
impl BenchTpsClient for BankClient {
fn send_transaction(&self, transaction: Transaction) -> Result<Signature> {
AsyncClient::async_send_transaction(self, transaction).map_err(|err| err.into())
}
fn send_batch(&self, transactions: Vec<Transaction>) -> Result<()> {
AsyncClient::async_send_batch(self, transactions).map_err(|err| err.into())
}
fn get_latest_blockhash(&self) -> Result<Hash> {
SyncClient::get_latest_blockhash(self).map_err(|err| err.into())
}
fn get_latest_blockhash_with_commitment(
&self,
commitment_config: CommitmentConfig,
) -> Result<(Hash, u64)> {
SyncClient::get_latest_blockhash_with_commitment(self, commitment_config)
.map_err(|err| err.into())
}
fn get_transaction_count(&self) -> Result<u64> {
SyncClient::get_transaction_count(self).map_err(|err| err.into())
}
fn get_transaction_count_with_commitment(
&self,
commitment_config: CommitmentConfig,
) -> Result<u64> {
SyncClient::get_transaction_count_with_commitment(self, commitment_config)
.map_err(|err| err.into())
}
fn get_epoch_info(&self) -> Result<EpochInfo> {
SyncClient::get_epoch_info(self).map_err(|err| err.into())
}
fn get_balance(&self, pubkey: &Pubkey) -> Result<u64> {
SyncClient::get_balance(self, pubkey).map_err(|err| err.into())
}
fn get_balance_with_commitment(
&self,
pubkey: &Pubkey,
commitment_config: CommitmentConfig,
) -> Result<u64> {
SyncClient::get_balance_with_commitment(self, pubkey, commitment_config)
.map_err(|err| err.into())
}
fn get_fee_for_message(&self, message: &Message) -> Result<u64> {
SyncClient::get_fee_for_message(self, message).map_err(|err| err.into())
}
fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> Result<u64> {
SyncClient::get_minimum_balance_for_rent_exemption(self, data_len).map_err(|err| err.into())
}
fn addr(&self) -> String {
"Local BankClient".to_string()
}
fn request_airdrop_with_blockhash(
&self,
_pubkey: &Pubkey,
_lamports: u64,
_recent_blockhash: &Hash,
) -> Result<Signature> {
// BankClient doesn't support airdrops
Err(BenchTpsError::AirdropFailure)
}
}

View File

@@ -1,83 +0,0 @@
use {
crate::bench_tps_client::{BenchTpsClient, Result},
solana_client::rpc_client::RpcClient,
solana_sdk::{
commitment_config::CommitmentConfig, epoch_info::EpochInfo, hash::Hash, message::Message,
pubkey::Pubkey, signature::Signature, transaction::Transaction,
},
};
impl BenchTpsClient for RpcClient {
fn send_transaction(&self, transaction: Transaction) -> Result<Signature> {
RpcClient::send_transaction(self, &transaction).map_err(|err| err.into())
}
fn send_batch(&self, transactions: Vec<Transaction>) -> Result<()> {
for transaction in transactions {
BenchTpsClient::send_transaction(self, transaction)?;
}
Ok(())
}
fn get_latest_blockhash(&self) -> Result<Hash> {
RpcClient::get_latest_blockhash(self).map_err(|err| err.into())
}
fn get_latest_blockhash_with_commitment(
&self,
commitment_config: CommitmentConfig,
) -> Result<(Hash, u64)> {
RpcClient::get_latest_blockhash_with_commitment(self, commitment_config)
.map_err(|err| err.into())
}
fn get_transaction_count(&self) -> Result<u64> {
RpcClient::get_transaction_count(self).map_err(|err| err.into())
}
fn get_transaction_count_with_commitment(
&self,
commitment_config: CommitmentConfig,
) -> Result<u64> {
RpcClient::get_transaction_count_with_commitment(self, commitment_config)
.map_err(|err| err.into())
}
fn get_epoch_info(&self) -> Result<EpochInfo> {
RpcClient::get_epoch_info(self).map_err(|err| err.into())
}
fn get_balance(&self, pubkey: &Pubkey) -> Result<u64> {
RpcClient::get_balance(self, pubkey).map_err(|err| err.into())
}
fn get_balance_with_commitment(
&self,
pubkey: &Pubkey,
commitment_config: CommitmentConfig,
) -> Result<u64> {
RpcClient::get_balance_with_commitment(self, pubkey, commitment_config)
.map(|res| res.value)
.map_err(|err| err.into())
}
fn get_fee_for_message(&self, message: &Message) -> Result<u64> {
RpcClient::get_fee_for_message(self, message).map_err(|err| err.into())
}
fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> Result<u64> {
RpcClient::get_minimum_balance_for_rent_exemption(self, data_len).map_err(|err| err.into())
}
fn addr(&self) -> String {
self.url()
}
fn request_airdrop_with_blockhash(
&self,
pubkey: &Pubkey,
lamports: u64,
recent_blockhash: &Hash,
) -> Result<Signature> {
RpcClient::request_airdrop_with_blockhash(self, pubkey, lamports, recent_blockhash)
.map_err(|err| err.into())
}
}

View File

@@ -1,86 +0,0 @@
use {
crate::bench_tps_client::{BenchTpsClient, Result},
solana_client::thin_client::ThinClient,
solana_sdk::{
client::{AsyncClient, Client, SyncClient},
commitment_config::CommitmentConfig,
epoch_info::EpochInfo,
hash::Hash,
message::Message,
pubkey::Pubkey,
signature::Signature,
transaction::Transaction,
},
};
impl BenchTpsClient for ThinClient {
fn send_transaction(&self, transaction: Transaction) -> Result<Signature> {
AsyncClient::async_send_transaction(self, transaction).map_err(|err| err.into())
}
fn send_batch(&self, transactions: Vec<Transaction>) -> Result<()> {
AsyncClient::async_send_batch(self, transactions).map_err(|err| err.into())
}
fn get_latest_blockhash(&self) -> Result<Hash> {
SyncClient::get_latest_blockhash(self).map_err(|err| err.into())
}
fn get_latest_blockhash_with_commitment(
&self,
commitment_config: CommitmentConfig,
) -> Result<(Hash, u64)> {
SyncClient::get_latest_blockhash_with_commitment(self, commitment_config)
.map_err(|err| err.into())
}
fn get_transaction_count(&self) -> Result<u64> {
SyncClient::get_transaction_count(self).map_err(|err| err.into())
}
fn get_transaction_count_with_commitment(
&self,
commitment_config: CommitmentConfig,
) -> Result<u64> {
SyncClient::get_transaction_count_with_commitment(self, commitment_config)
.map_err(|err| err.into())
}
fn get_epoch_info(&self) -> Result<EpochInfo> {
SyncClient::get_epoch_info(self).map_err(|err| err.into())
}
fn get_balance(&self, pubkey: &Pubkey) -> Result<u64> {
SyncClient::get_balance(self, pubkey).map_err(|err| err.into())
}
fn get_balance_with_commitment(
&self,
pubkey: &Pubkey,
commitment_config: CommitmentConfig,
) -> Result<u64> {
SyncClient::get_balance_with_commitment(self, pubkey, commitment_config)
.map_err(|err| err.into())
}
fn get_fee_for_message(&self, message: &Message) -> Result<u64> {
SyncClient::get_fee_for_message(self, message).map_err(|err| err.into())
}
fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> Result<u64> {
SyncClient::get_minimum_balance_for_rent_exemption(self, data_len).map_err(|err| err.into())
}
fn addr(&self) -> String {
Client::tpu_addr(self)
}
fn request_airdrop_with_blockhash(
&self,
pubkey: &Pubkey,
lamports: u64,
recent_blockhash: &Hash,
) -> Result<Signature> {
self.rpc_client()
.request_airdrop_with_blockhash(pubkey, lamports, recent_blockhash)
.map_err(|err| err.into())
}
}

View File

@@ -1,99 +0,0 @@
use {
crate::bench_tps_client::{BenchTpsClient, Result},
solana_client::tpu_client::TpuClient,
solana_sdk::{
commitment_config::CommitmentConfig, epoch_info::EpochInfo, hash::Hash, message::Message,
pubkey::Pubkey, signature::Signature, transaction::Transaction,
},
};
impl BenchTpsClient for TpuClient {
fn send_transaction(&self, transaction: Transaction) -> Result<Signature> {
let signature = transaction.signatures[0];
self.try_send_transaction(&transaction)?;
Ok(signature)
}
fn send_batch(&self, transactions: Vec<Transaction>) -> Result<()> {
for transaction in transactions {
BenchTpsClient::send_transaction(self, transaction)?;
}
Ok(())
}
fn get_latest_blockhash(&self) -> Result<Hash> {
self.rpc_client()
.get_latest_blockhash()
.map_err(|err| err.into())
}
fn get_latest_blockhash_with_commitment(
&self,
commitment_config: CommitmentConfig,
) -> Result<(Hash, u64)> {
self.rpc_client()
.get_latest_blockhash_with_commitment(commitment_config)
.map_err(|err| err.into())
}
fn get_transaction_count(&self) -> Result<u64> {
self.rpc_client()
.get_transaction_count()
.map_err(|err| err.into())
}
fn get_transaction_count_with_commitment(
&self,
commitment_config: CommitmentConfig,
) -> Result<u64> {
self.rpc_client()
.get_transaction_count_with_commitment(commitment_config)
.map_err(|err| err.into())
}
fn get_epoch_info(&self) -> Result<EpochInfo> {
self.rpc_client().get_epoch_info().map_err(|err| err.into())
}
fn get_balance(&self, pubkey: &Pubkey) -> Result<u64> {
self.rpc_client()
.get_balance(pubkey)
.map_err(|err| err.into())
}
fn get_balance_with_commitment(
&self,
pubkey: &Pubkey,
commitment_config: CommitmentConfig,
) -> Result<u64> {
self.rpc_client()
.get_balance_with_commitment(pubkey, commitment_config)
.map(|res| res.value)
.map_err(|err| err.into())
}
fn get_fee_for_message(&self, message: &Message) -> Result<u64> {
self.rpc_client()
.get_fee_for_message(message)
.map_err(|err| err.into())
}
fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> Result<u64> {
self.rpc_client()
.get_minimum_balance_for_rent_exemption(data_len)
.map_err(|err| err.into())
}
fn addr(&self) -> String {
self.rpc_client().url()
}
fn request_airdrop_with_blockhash(
&self,
pubkey: &Pubkey,
lamports: u64,
recent_blockhash: &Hash,
) -> Result<Signature> {
self.rpc_client()
.request_airdrop_with_blockhash(pubkey, lamports, recent_blockhash)
.map_err(|err| err.into())
}
}

View File

@@ -1,7 +1,6 @@
use {
clap::{crate_description, crate_name, App, Arg, ArgMatches},
solana_clap_utils::input_validators::{is_url, is_url_or_moniker},
solana_cli_config::{ConfigInput, CONFIG_FILE},
solana_faucet::faucet::FAUCET_PORT,
solana_sdk::{
fee_calculator::FeeRateGovernor,
pubkey::Pubkey,
@@ -12,28 +11,10 @@ use {
const NUM_LAMPORTS_PER_ACCOUNT_DEFAULT: u64 = solana_sdk::native_token::LAMPORTS_PER_SOL;
pub enum ExternalClientType {
// Submits transactions to an Rpc node using an RpcClient
RpcClient,
// Submits transactions directly to leaders using a ThinClient, broadcasting to multiple
// leaders when num_nodes > 1
ThinClient,
// Submits transactions directly to leaders using a TpuClient, broadcasting to upcoming leaders
// via TpuClient default configuration
TpuClient,
}
impl Default for ExternalClientType {
fn default() -> Self {
Self::ThinClient
}
}
/// Holds the configuration for a single run of the benchmark
pub struct Config {
pub entrypoint_addr: SocketAddr,
pub json_rpc_url: String,
pub websocket_url: String,
pub faucet_addr: SocketAddr,
pub id: Keypair,
pub threads: usize,
pub num_nodes: usize,
@@ -50,16 +31,13 @@ pub struct Config {
pub num_lamports_per_account: u64,
pub target_slots_per_epoch: u64,
pub target_node: Option<Pubkey>,
pub external_client_type: ExternalClientType,
pub use_quic: bool,
}
impl Default for Config {
fn default() -> Config {
Config {
entrypoint_addr: SocketAddr::from(([127, 0, 0, 1], 8001)),
json_rpc_url: ConfigInput::default().json_rpc_url,
websocket_url: ConfigInput::default().websocket_url,
faucet_addr: SocketAddr::from(([127, 0, 0, 1], FAUCET_PORT)),
id: Keypair::new(),
threads: 4,
num_nodes: 1,
@@ -76,8 +54,6 @@ impl Default for Config {
num_lamports_per_account: NUM_LAMPORTS_PER_ACCOUNT_DEFAULT,
target_slots_per_epoch: 0,
target_node: None,
external_client_type: ExternalClientType::default(),
use_quic: false,
}
}
}
@@ -86,42 +62,6 @@ impl Default for Config {
pub fn build_args<'a, 'b>(version: &'b str) -> App<'a, 'b> {
App::new(crate_name!()).about(crate_description!())
.version(version)
.arg({
let arg = Arg::with_name("config_file")
.short("C")
.long("config")
.value_name("FILEPATH")
.takes_value(true)
.global(true)
.help("Configuration file to use");
if let Some(ref config_file) = *CONFIG_FILE {
arg.default_value(config_file)
} else {
arg
}
})
.arg(
Arg::with_name("json_rpc_url")
.short("u")
.long("url")
.value_name("URL_OR_MONIKER")
.takes_value(true)
.global(true)
.validator(is_url_or_moniker)
.help(
"URL for Solana's JSON RPC or moniker (or their first letter): \
[mainnet-beta, testnet, devnet, localhost]",
),
)
.arg(
Arg::with_name("websocket_url")
.long("ws")
.value_name("URL")
.takes_value(true)
.global(true)
.validator(is_url)
.help("WebSocket URL for the solana cluster"),
)
.arg(
Arg::with_name("entrypoint")
.short("n")
@@ -136,8 +76,7 @@ pub fn build_args<'a, 'b>(version: &'b str) -> App<'a, 'b> {
.long("faucet")
.value_name("HOST:PORT")
.takes_value(true)
.hidden(true)
.help("Deprecated. BenchTps no longer queries the faucet directly"),
.help("Location of the faucet; defaults to entrypoint:FAUCET_PORT"),
)
.arg(
Arg::with_name("identity")
@@ -252,27 +191,6 @@ pub fn build_args<'a, 'b>(version: &'b str) -> App<'a, 'b> {
"Wait until epochs are this many slots long.",
),
)
.arg(
Arg::with_name("rpc_client")
.long("use-rpc-client")
.conflicts_with("tpu_client")
.takes_value(false)
.help("Submit transactions with a RpcClient")
)
.arg(
Arg::with_name("tpu_client")
.long("use-tpu-client")
.conflicts_with("rpc_client")
.takes_value(false)
.help("Submit transactions with a TpuClient")
)
.arg(
Arg::with_name("tpu_use_quic")
.long("tpu-use-quic")
.takes_value(false)
.help("Submit transactions via QUIC; only affects ThinClient (default) \
or TpuClient sends"),
)
}
/// Parses a clap `ArgMatches` structure into a `Config`
@@ -283,45 +201,6 @@ pub fn build_args<'a, 'b>(version: &'b str) -> App<'a, 'b> {
pub fn extract_args(matches: &ArgMatches) -> Config {
let mut args = Config::default();
let config = if let Some(config_file) = matches.value_of("config_file") {
solana_cli_config::Config::load(config_file).unwrap_or_default()
} else {
solana_cli_config::Config::default()
};
let (_, json_rpc_url) = ConfigInput::compute_json_rpc_url_setting(
matches.value_of("json_rpc_url").unwrap_or(""),
&config.json_rpc_url,
);
args.json_rpc_url = json_rpc_url;
let (_, websocket_url) = ConfigInput::compute_websocket_url_setting(
matches.value_of("websocket_url").unwrap_or(""),
&config.websocket_url,
matches.value_of("json_rpc_url").unwrap_or(""),
&config.json_rpc_url,
);
args.websocket_url = websocket_url;
let (_, id_path) = ConfigInput::compute_keypair_path_setting(
matches.value_of("identity").unwrap_or(""),
&config.keypair_path,
);
if let Ok(id) = read_keypair_file(id_path) {
args.id = id;
} else if matches.is_present("identity") {
panic!("could not parse identity path");
}
if matches.is_present("tpu_client") {
args.external_client_type = ExternalClientType::TpuClient;
} else if matches.is_present("rpc_client") {
args.external_client_type = ExternalClientType::RpcClient;
}
if matches.is_present("tpu_use_quic") {
args.use_quic = true;
}
if let Some(addr) = matches.value_of("entrypoint") {
args.entrypoint_addr = solana_net_utils::parse_host_port(addr).unwrap_or_else(|e| {
eprintln!("failed to parse entrypoint address: {}", e);
@@ -329,6 +208,18 @@ pub fn extract_args(matches: &ArgMatches) -> Config {
});
}
if let Some(addr) = matches.value_of("faucet") {
args.faucet_addr = solana_net_utils::parse_host_port(addr).unwrap_or_else(|e| {
eprintln!("failed to parse faucet address: {}", e);
exit(1)
});
}
if matches.is_present("identity") {
args.id = read_keypair_file(matches.value_of("identity").unwrap())
.expect("can't read client identity");
}
if let Some(t) = matches.value_of("threads") {
args.threads = t.to_string().parse().expect("can't parse threads");
}

View File

@@ -1,72 +0,0 @@
use {
crate::{
bench::{fund_keypairs, generate_and_fund_keypairs},
bench_tps_client::BenchTpsClient,
},
log::*,
solana_genesis::Base64Account,
solana_sdk::signature::{Keypair, Signer},
std::{collections::HashMap, fs::File, path::Path, process::exit, sync::Arc},
};
pub fn get_keypairs<T>(
client: Arc<T>,
id: &Keypair,
keypair_count: usize,
num_lamports_per_account: u64,
client_ids_and_stake_file: &str,
read_from_client_file: bool,
) -> Vec<Keypair>
where
T: 'static + BenchTpsClient + Send + Sync,
{
if read_from_client_file {
let path = Path::new(client_ids_and_stake_file);
let file = File::open(path).unwrap();
info!("Reading {}", client_ids_and_stake_file);
let accounts: HashMap<String, Base64Account> = serde_yaml::from_reader(file).unwrap();
let mut keypairs = vec![];
let mut last_balance = 0;
accounts
.into_iter()
.for_each(|(keypair, primordial_account)| {
let bytes: Vec<u8> = serde_json::from_str(keypair.as_str()).unwrap();
keypairs.push(Keypair::from_bytes(&bytes).unwrap());
last_balance = primordial_account.balance;
});
if keypairs.len() < keypair_count {
eprintln!(
"Expected {} accounts in {}, only received {} (--tx_count mismatch?)",
keypair_count,
client_ids_and_stake_file,
keypairs.len(),
);
exit(1);
}
// Sort keypairs so that do_bench_tps() uses the same subset of accounts for each run.
// This prevents the amount of storage needed for bench-tps accounts from creeping up
// across multiple runs.
keypairs.sort_by_key(|x| x.pubkey().to_string());
fund_keypairs(
client,
id,
&keypairs,
keypairs.len().saturating_sub(keypair_count) as u64,
last_balance,
)
.unwrap_or_else(|e| {
eprintln!("Error could not fund keys: {:?}", e);
exit(1);
});
keypairs
} else {
generate_and_fund_keypairs(client, id, keypair_count, num_lamports_per_account)
.unwrap_or_else(|e| {
eprintln!("Error could not fund keys: {:?}", e);
exit(1);
})
}
}

View File

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

View File

@@ -2,19 +2,15 @@
use {
log::*,
solana_bench_tps::{
bench::{do_bench_tps, generate_keypairs},
cli::{self, ExternalClientType},
keypairs::get_keypairs,
},
solana_client::{
connection_cache,
rpc_client::RpcClient,
tpu_client::{TpuClient, TpuClientConfig},
bench::{do_bench_tps, generate_and_fund_keypairs, generate_keypairs},
cli,
},
solana_genesis::Base64Account,
solana_gossip::gossip_service::{discover_cluster, get_client, get_multi_client},
solana_sdk::{
commitment_config::CommitmentConfig, fee_calculator::FeeRateGovernor, system_program,
fee_calculator::FeeRateGovernor,
signature::{Keypair, Signer},
system_program,
},
solana_streamer::socket::SocketAddrSpace,
std::{collections::HashMap, fs::File, io::prelude::*, path::Path, process::exit, sync::Arc},
@@ -25,15 +21,14 @@ pub const NUM_SIGNATURES_FOR_TXS: u64 = 100_000 * 60 * 60 * 24 * 7;
fn main() {
solana_logger::setup_with_default("solana=info");
solana_metrics::set_panic_hook("bench-tps", /*version:*/ None);
solana_metrics::set_panic_hook("bench-tps");
let matches = cli::build_args(solana_version::version!()).get_matches();
let cli_config = cli::extract_args(&matches);
let cli::Config {
entrypoint_addr,
json_rpc_url,
websocket_url,
faucet_addr,
id,
num_nodes,
tx_count,
@@ -45,8 +40,6 @@ fn main() {
multi_client,
num_lamports_per_account,
target_node,
external_client_type,
use_quic,
..
} = &cli_config;
@@ -82,93 +75,83 @@ fn main() {
}
info!("Connecting to the cluster");
let nodes = discover_cluster(entrypoint_addr, *num_nodes, SocketAddrSpace::Unspecified)
.unwrap_or_else(|err| {
eprintln!("Failed to discover {} nodes: {:?}", num_nodes, err);
exit(1);
});
match external_client_type {
ExternalClientType::RpcClient => {
let client = Arc::new(RpcClient::new_with_commitment(
json_rpc_url.to_string(),
CommitmentConfig::confirmed(),
));
let keypairs = get_keypairs(
client.clone(),
id,
keypair_count,
*num_lamports_per_account,
client_ids_and_stake_file,
*read_from_client_file,
let client = if *multi_client {
let (client, num_clients) = get_multi_client(&nodes, &SocketAddrSpace::Unspecified);
if nodes.len() < num_clients {
eprintln!(
"Error: Insufficient nodes discovered. Expecting {} or more",
num_nodes
);
do_bench_tps(client, cli_config, keypairs);
exit(1);
}
ExternalClientType::ThinClient => {
let nodes = discover_cluster(entrypoint_addr, *num_nodes, SocketAddrSpace::Unspecified)
.unwrap_or_else(|err| {
eprintln!("Failed to discover {} nodes: {:?}", num_nodes, err);
exit(1);
});
if *use_quic {
connection_cache::set_use_quic(true);
Arc::new(client)
} else if let Some(target_node) = target_node {
info!("Searching for target_node: {:?}", target_node);
let mut target_client = None;
for node in nodes {
if node.id == *target_node {
target_client = Some(Arc::new(get_client(&[node], &SocketAddrSpace::Unspecified)));
break;
}
let client = if *multi_client {
let (client, num_clients) = get_multi_client(&nodes, &SocketAddrSpace::Unspecified);
if nodes.len() < num_clients {
eprintln!(
"Error: Insufficient nodes discovered. Expecting {} or more",
num_nodes
);
exit(1);
}
Arc::new(client)
} else if let Some(target_node) = target_node {
info!("Searching for target_node: {:?}", target_node);
let mut target_client = None;
for node in nodes {
if node.id == *target_node {
target_client =
Some(Arc::new(get_client(&[node], &SocketAddrSpace::Unspecified)));
break;
}
}
target_client.unwrap_or_else(|| {
eprintln!("Target node {} not found", target_node);
exit(1);
})
} else {
Arc::new(get_client(&nodes, &SocketAddrSpace::Unspecified))
};
let keypairs = get_keypairs(
client.clone(),
id,
keypair_count,
*num_lamports_per_account,
client_ids_and_stake_file,
*read_from_client_file,
);
do_bench_tps(client, cli_config, keypairs);
}
ExternalClientType::TpuClient => {
let rpc_client = Arc::new(RpcClient::new_with_commitment(
json_rpc_url.to_string(),
CommitmentConfig::confirmed(),
));
if *use_quic {
connection_cache::set_use_quic(true);
}
let client = Arc::new(
TpuClient::new(rpc_client, websocket_url, TpuClientConfig::default())
.unwrap_or_else(|err| {
eprintln!("Could not create TpuClient {:?}", err);
exit(1);
}),
);
let keypairs = get_keypairs(
client.clone(),
id,
target_client.unwrap_or_else(|| {
eprintln!("Target node {} not found", target_node);
exit(1);
})
} else {
Arc::new(get_client(&nodes, &SocketAddrSpace::Unspecified))
};
let keypairs = if *read_from_client_file {
let path = Path::new(&client_ids_and_stake_file);
let file = File::open(path).unwrap();
info!("Reading {}", client_ids_and_stake_file);
let accounts: HashMap<String, Base64Account> = serde_yaml::from_reader(file).unwrap();
let mut keypairs = vec![];
let mut last_balance = 0;
accounts
.into_iter()
.for_each(|(keypair, primordial_account)| {
let bytes: Vec<u8> = serde_json::from_str(keypair.as_str()).unwrap();
keypairs.push(Keypair::from_bytes(&bytes).unwrap());
last_balance = primordial_account.balance;
});
if keypairs.len() < keypair_count {
eprintln!(
"Expected {} accounts in {}, only received {} (--tx_count mismatch?)",
keypair_count,
*num_lamports_per_account,
client_ids_and_stake_file,
*read_from_client_file,
keypairs.len(),
);
do_bench_tps(client, cli_config, keypairs);
exit(1);
}
}
// Sort keypairs so that do_bench_tps() uses the same subset of accounts for each run.
// This prevents the amount of storage needed for bench-tps accounts from creeping up
// across multiple runs.
keypairs.sort_by_key(|x| x.pubkey().to_string());
keypairs
} else {
generate_and_fund_keypairs(
client.clone(),
Some(*faucet_addr),
id,
keypair_count,
*num_lamports_per_account,
)
.unwrap_or_else(|e| {
eprintln!("Error could not fund keys: {:?}", e);
exit(1);
})
};
do_bench_tps(client, cli_config, keypairs);
}

View File

@@ -1,64 +1,37 @@
#![allow(clippy::integer_arithmetic)]
use {
crossbeam_channel::unbounded,
serial_test::serial,
solana_bench_tps::{
bench::{do_bench_tps, generate_and_fund_keypairs},
cli::Config,
},
solana_client::{
rpc_client::RpcClient,
thin_client::create_client,
tpu_client::{TpuClient, TpuClientConfig},
},
solana_client::thin_client::create_client,
solana_core::validator::ValidatorConfig,
solana_faucet::faucet::{run_local_faucet, run_local_faucet_with_port},
solana_faucet::faucet::run_local_faucet_with_port,
solana_gossip::cluster_info::VALIDATOR_PORT_RANGE,
solana_local_cluster::{
local_cluster::{ClusterConfig, LocalCluster},
validator_configs::make_identical_validator_configs,
},
solana_rpc::rpc::JsonRpcConfig,
solana_sdk::{
commitment_config::CommitmentConfig,
signature::{Keypair, Signer},
},
solana_sdk::signature::{Keypair, Signer},
solana_streamer::socket::SocketAddrSpace,
solana_test_validator::TestValidator,
std::{sync::Arc, time::Duration},
std::{
sync::{mpsc::channel, Arc},
time::Duration,
},
};
fn test_bench_tps_local_cluster(config: Config) {
let native_instruction_processors = vec![];
solana_logger::setup();
let faucet_keypair = Keypair::new();
let faucet_pubkey = faucet_keypair.pubkey();
let (addr_sender, addr_receiver) = unbounded();
run_local_faucet_with_port(faucet_keypair, addr_sender, None, 0);
let faucet_addr = addr_receiver
.recv_timeout(Duration::from_secs(2))
.expect("run_local_faucet")
.expect("faucet_addr");
const NUM_NODES: usize = 1;
let mut validator_config = ValidatorConfig::default_for_test();
validator_config.rpc_config = JsonRpcConfig {
faucet_addr: Some(faucet_addr),
..JsonRpcConfig::default_for_test()
};
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 {
rpc_config: JsonRpcConfig {
faucet_addr: Some(faucet_addr),
..JsonRpcConfig::default_for_test()
},
..ValidatorConfig::default_for_test()
},
&ValidatorConfig::default(),
NUM_NODES,
),
native_instruction_processors,
@@ -67,55 +40,31 @@ fn test_bench_tps_local_cluster(config: Config) {
SocketAddrSpace::Unspecified,
);
cluster.transfer(&cluster.funding_keypair, &faucet_pubkey, 100_000_000);
let faucet_keypair = Keypair::new();
cluster.transfer(
&cluster.funding_keypair,
&faucet_keypair.pubkey(),
100_000_000,
);
let client = Arc::new(create_client(
cluster.entry_point_info.rpc,
cluster.entry_point_info.tpu,
(cluster.entry_point_info.rpc, cluster.entry_point_info.tpu),
VALIDATOR_PORT_RANGE,
));
let (addr_sender, addr_receiver) = channel();
run_local_faucet_with_port(faucet_keypair, addr_sender, None, 0);
let faucet_addr = addr_receiver
.recv_timeout(Duration::from_secs(2))
.expect("run_local_faucet")
.expect("faucet_addr");
let lamports_per_account = 100;
let keypair_count = config.tx_count * config.keypair_multiplier;
let keypairs = generate_and_fund_keypairs(
client.clone(),
&config.id,
keypair_count,
lamports_per_account,
)
.unwrap();
let _total = do_bench_tps(client, config, keypairs);
#[cfg(not(debug_assertions))]
assert!(_total > 100);
}
fn test_bench_tps_test_validator(config: Config) {
solana_logger::setup();
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
let rpc_client = Arc::new(RpcClient::new_with_commitment(
test_validator.rpc_url(),
CommitmentConfig::processed(),
));
let websocket_url = test_validator.rpc_pubsub_url();
let client =
Arc::new(TpuClient::new(rpc_client, &websocket_url, TpuClientConfig::default()).unwrap());
let lamports_per_account = 100;
let keypair_count = config.tx_count * config.keypair_multiplier;
let keypairs = generate_and_fund_keypairs(
client.clone(),
Some(faucet_addr),
&config.id,
keypair_count,
lamports_per_account,
@@ -137,13 +86,3 @@ fn test_bench_tps_local_cluster_solana() {
..Config::default()
});
}
#[test]
#[serial]
fn test_bench_tps_tpu_client() {
test_bench_tps_test_validator(Config {
tx_count: 100,
duration: Duration::from_secs(10),
..Config::default()
});
}

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-bloom"
version = "1.11.0"
version = "1.9.5"
description = "Solana bloom filter"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@@ -12,14 +12,14 @@ edition = "2021"
[dependencies]
bv = { version = "0.11.1", features = ["serde"] }
fnv = "1.0.7"
log = "0.4.14"
rand = "0.7.0"
serde = { version = "1.0.133", features = ["rc"] }
rayon = "1.5.1"
serde = { version = "1.0.136", features = ["rc"] }
serde_derive = "1.0.103"
solana-frozen-abi = { path = "../frozen-abi", version = "=1.11.0" }
solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "=1.11.0" }
solana-sdk = { path = "../sdk", version = "=1.11.0" }
solana-frozen-abi = { path = "../frozen-abi", version = "=1.9.5" }
solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "=1.9.5" }
solana-sdk = { path = "../sdk", version = "=1.9.5" }
log = "0.4.14"
[lib]
crate-type = ["lib"]

View File

@@ -1,7 +1,3 @@
---
title: Handle Duplicate Block
---
# Leader Duplicate Block Slashing
This design describes how the cluster slashes leaders that produce duplicate

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-bucket-map"
version = "1.11.0"
version = "1.9.5"
description = "solana-bucket-map"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-bucket-map"
@@ -11,18 +11,15 @@ license = "Apache-2.0"
edition = "2021"
[dependencies]
log = { version = "0.4.11" }
memmap2 = "0.5.3"
modular-bitfield = "0.11.2"
rand = "0.7.0"
solana-measure = { path = "../measure", version = "=1.11.0" }
solana-sdk = { path = "../sdk", version = "=1.11.0" }
tempfile = "3.3.0"
[dev-dependencies]
fs_extra = "1.2.0"
rayon = "1.5.0"
solana-logger = { path = "../logger", version = "=1.11.0" }
solana-logger = { path = "../logger", version = "=1.9.5" }
solana-sdk = { path = "../sdk", version = "=1.9.5" }
memmap2 = "0.5.0"
log = { version = "0.4.11" }
solana-measure = { path = "../measure", version = "=1.9.5" }
rand = "0.7.0"
fs_extra = "1.2.0"
tempfile = "3.2.0"
[lib]
crate-type = ["lib"]

View File

@@ -3,7 +3,7 @@ use {
bucket_item::BucketItem,
bucket_map::BucketMapError,
bucket_stats::BucketMapStats,
bucket_storage::{BucketStorage, Uid, DEFAULT_CAPACITY_POW2},
bucket_storage::{BucketStorage, Uid, DEFAULT_CAPACITY_POW2, UID_UNLOCKED},
index_entry::IndexEntry,
MaxSearch, RefCount,
},
@@ -17,7 +17,7 @@ use {
ops::RangeBounds,
path::PathBuf,
sync::{
atomic::{AtomicU64, AtomicUsize, Ordering},
atomic::{AtomicUsize, Ordering},
Arc, Mutex,
},
},
@@ -81,7 +81,6 @@ impl<T: Clone + Copy> Bucket<T> {
drives: Arc<Vec<PathBuf>>,
max_search: MaxSearch,
stats: Arc<BucketMapStats>,
count: Arc<AtomicU64>,
) -> Self {
let index = BucketStorage::new(
Arc::clone(&drives),
@@ -89,7 +88,6 @@ impl<T: Clone + Copy> Bucket<T> {
std::mem::size_of::<IndexEntry>() as u64,
max_search,
Arc::clone(&stats.index),
count,
);
Self {
random: thread_rng().gen(),
@@ -102,10 +100,14 @@ impl<T: Clone + Copy> Bucket<T> {
}
}
pub fn bucket_len(&self) -> u64 {
self.index.used.load(Ordering::Relaxed)
}
pub fn keys(&self) -> Vec<Pubkey> {
let mut rv = vec![];
for i in 0..self.index.capacity() {
if self.index.is_free(i) {
if self.index.uid(i) == UID_UNLOCKED {
continue;
}
let ix: &IndexEntry = self.index.get(i);
@@ -118,10 +120,10 @@ impl<T: Clone + Copy> Bucket<T> {
where
R: RangeBounds<Pubkey>,
{
let mut result = Vec::with_capacity(self.index.count.load(Ordering::Relaxed) as usize);
let mut result = Vec::with_capacity(self.index.used.load(Ordering::Relaxed) as usize);
for i in 0..self.index.capacity() {
let ii = i % self.index.capacity();
if self.index.is_free(ii) {
if self.index.uid(ii) == UID_UNLOCKED {
continue;
}
let ix: &IndexEntry = self.index.get(ii);
@@ -154,7 +156,7 @@ impl<T: Clone + Copy> Bucket<T> {
let ix = Self::bucket_index_ix(index, key, random);
for i in ix..ix + index.max_search() {
let ii = i % index.capacity();
if index.is_free(ii) {
if index.uid(ii) == UID_UNLOCKED {
continue;
}
let elem: &mut IndexEntry = index.get_mut(ii);
@@ -173,7 +175,7 @@ impl<T: Clone + Copy> Bucket<T> {
let ix = Self::bucket_index_ix(index, key, random);
for i in ix..ix + index.max_search() {
let ii = i % index.capacity();
if index.is_free(ii) {
if index.uid(ii) == UID_UNLOCKED {
continue;
}
let elem: &IndexEntry = index.get(ii);
@@ -185,23 +187,26 @@ impl<T: Clone + Copy> Bucket<T> {
}
fn bucket_create_key(
index: &mut BucketStorage,
index: &BucketStorage,
key: &Pubkey,
elem_uid: Uid,
random: u64,
is_resizing: bool,
) -> Result<u64, BucketMapError> {
let ix = Self::bucket_index_ix(index, key, random);
for i in ix..ix + index.max_search() {
let ii = i as u64 % index.capacity();
if !index.is_free(ii) {
if index.uid(ii) != UID_UNLOCKED {
continue;
}
index.allocate(ii, elem_uid, is_resizing).unwrap();
let elem: &mut IndexEntry = index.get_mut(ii);
// These fields will be overwritten after allocation by callers.
index.allocate(ii, elem_uid).unwrap();
let mut elem: &mut IndexEntry = index.get_mut(ii);
elem.key = *key;
// These will be overwritten after allocation by callers.
// Since this part of the mmapped file could have previously been used by someone else, there can be garbage here.
elem.init(key);
elem.ref_count = 0;
elem.storage_offset = 0;
elem.storage_capacity_when_created_pow2 = 0;
elem.num_slots = 0;
//debug!( "INDEX ALLOC {:?} {} {} {}", key, ii, index.capacity, elem_uid );
return Ok(ii);
}
@@ -220,14 +225,8 @@ impl<T: Clone + Copy> Bucket<T> {
Some(elem.ref_count)
}
fn create_key(&mut self, key: &Pubkey) -> Result<u64, BucketMapError> {
Self::bucket_create_key(
&mut self.index,
key,
IndexEntry::key_uid(key),
self.random,
false,
)
fn create_key(&self, key: &Pubkey) -> Result<u64, BucketMapError> {
Self::bucket_create_key(&self.index, key, IndexEntry::key_uid(key), self.random)
}
pub fn read_value(&self, key: &Pubkey) -> Option<(&[T], RefCount)> {
@@ -257,17 +256,16 @@ impl<T: Clone + Copy> Bucket<T> {
Some(res) => res,
};
elem.ref_count = ref_count;
let elem_uid = self.index.uid_unchecked(elem_ix);
let elem_uid = self.index.uid(elem_ix);
let bucket_ix = elem.data_bucket_ix();
let current_bucket = &self.data[bucket_ix as usize];
let num_slots = data.len() as u64;
if best_fit_bucket == bucket_ix && elem.num_slots > 0 {
// in place update
let elem_loc = elem.data_loc(current_bucket);
let slice: &mut [T] = current_bucket.get_mut_cell_slice(elem_loc, data.len() as u64);
assert_eq!(current_bucket.uid(elem_loc), Some(elem_uid));
elem.num_slots = num_slots;
slice.copy_from_slice(data);
assert!(current_bucket.uid(elem_loc) == elem_uid);
elem.num_slots = data.len() as u64;
slice.clone_from_slice(data);
Ok(())
} else {
// need to move the allocation to a best fit spot
@@ -277,21 +275,18 @@ impl<T: Clone + Copy> Bucket<T> {
let pos = thread_rng().gen_range(0, cap);
for i in pos..pos + self.index.max_search() {
let ix = i % cap;
if best_bucket.is_free(ix) {
if best_bucket.uid(ix) == UID_UNLOCKED {
let elem_loc = elem.data_loc(current_bucket);
let old_slots = elem.num_slots;
elem.set_storage_offset(ix);
elem.set_storage_capacity_when_created_pow2(best_bucket.capacity_pow2);
elem.num_slots = num_slots;
if old_slots > 0 {
let current_bucket = &mut self.data[bucket_ix as usize];
if elem.num_slots > 0 {
current_bucket.free(elem_loc, elem_uid);
}
elem.storage_offset = ix;
elem.storage_capacity_when_created_pow2 = best_bucket.capacity_pow2;
elem.num_slots = data.len() as u64;
//debug!( "DATA ALLOC {:?} {} {} {}", key, elem.data_location, best_bucket.capacity, elem_uid );
if num_slots > 0 {
let best_bucket = &mut self.data[best_fit_bucket as usize];
best_bucket.allocate(ix, elem_uid, false).unwrap();
let slice = best_bucket.get_mut_cell_slice(ix, num_slots);
if elem.num_slots > 0 {
best_bucket.allocate(ix, elem_uid).unwrap();
let slice = best_bucket.get_mut_cell_slice(ix, data.len() as u64);
slice.copy_from_slice(data);
}
return Ok(());
@@ -303,12 +298,10 @@ impl<T: Clone + Copy> Bucket<T> {
pub fn delete_key(&mut self, key: &Pubkey) {
if let Some((elem, elem_ix)) = self.find_entry(key) {
let elem_uid = self.index.uid_unchecked(elem_ix);
let elem_uid = self.index.uid(elem_ix);
if elem.num_slots > 0 {
let ix = elem.data_bucket_ix() as usize;
let data_bucket = &self.data[ix];
let data_bucket = &self.data[elem.data_bucket_ix() as usize];
let loc = elem.data_loc(data_bucket);
let data_bucket = &mut self.data[ix];
//debug!( "DATA FREE {:?} {} {} {}", key, elem.data_location, data_bucket.capacity, elem_uid );
data_bucket.free(loc, elem_uid);
}
@@ -326,7 +319,7 @@ impl<T: Clone + Copy> Bucket<T> {
//increasing the capacity by ^4 reduces the
//likelyhood of a re-index collision of 2^(max_search)^2
//1 in 2^32
let mut index = BucketStorage::new_with_capacity(
let index = BucketStorage::new_with_capacity(
Arc::clone(&self.drives),
1,
std::mem::size_of::<IndexEntry>() as u64,
@@ -334,16 +327,14 @@ impl<T: Clone + Copy> Bucket<T> {
self.index.capacity_pow2 + i, // * 2,
self.index.max_search,
Arc::clone(&self.stats.index),
Arc::clone(&self.index.count),
);
let random = thread_rng().gen();
let mut valid = true;
for ix in 0..self.index.capacity() {
let uid = self.index.uid(ix);
if let Some(uid) = uid {
if UID_UNLOCKED != uid {
let elem: &IndexEntry = self.index.get(ix);
let new_ix =
Self::bucket_create_key(&mut index, &elem.key, uid, random, true);
let new_ix = Self::bucket_create_key(&index, &elem.key, uid, random);
if new_ix.is_err() {
valid = false;
break;
@@ -400,7 +391,6 @@ impl<T: Clone + Copy> Bucket<T> {
Self::elem_size(),
self.index.max_search,
Arc::clone(&self.stats.data),
Arc::default(),
))
}
self.data.push(bucket);

View File

@@ -30,13 +30,14 @@ impl<T: Clone + Copy> BucketApi<T> {
drives: Arc<Vec<PathBuf>>,
max_search: MaxSearch,
stats: Arc<BucketMapStats>,
count: Arc<AtomicU64>,
) -> Self {
Self {
drives,
max_search,
stats,
bucket: RwLock::default(),
count: Arc::default(),
count,
}
}
@@ -72,7 +73,12 @@ impl<T: Clone + Copy> BucketApi<T> {
}
pub fn bucket_len(&self) -> u64 {
self.count.load(Ordering::Relaxed)
self.bucket
.read()
.unwrap()
.as_ref()
.map(|bucket| bucket.bucket_len())
.unwrap_or_default()
}
pub fn delete_key(&self, key: &Pubkey) {
@@ -89,11 +95,11 @@ impl<T: Clone + Copy> BucketApi<T> {
Arc::clone(&self.drives),
self.max_search,
Arc::clone(&self.stats),
Arc::clone(&self.count),
));
} else {
let write = bucket.as_mut().unwrap();
write.handle_delayed_grows();
self.count.store(write.bucket_len(), Ordering::Relaxed);
}
bucket
}

View File

@@ -79,14 +79,21 @@ impl<T: Clone + Copy + Debug> BucketMap<T> {
});
let drives = Arc::new(drives);
let stats = Arc::default();
let buckets = (0..config.max_buckets)
.into_iter()
.map(|_| {
let mut per_bucket_count = Vec::with_capacity(config.max_buckets);
per_bucket_count.resize_with(config.max_buckets, Arc::default);
let stats = Arc::new(BucketMapStats {
per_bucket_count,
..BucketMapStats::default()
});
let buckets = stats
.per_bucket_count
.iter()
.map(|per_bucket_count| {
Arc::new(BucketApi::new(
Arc::clone(&drives),
max_search,
Arc::clone(&stats),
Arc::clone(per_bucket_count),
))
})
.collect();

View File

@@ -14,4 +14,5 @@ pub struct BucketStats {
pub struct BucketMapStats {
pub index: Arc<BucketStats>,
pub data: Arc<BucketStats>,
pub per_bucket_count: Vec<Arc<AtomicU64>>,
}

View File

@@ -35,42 +35,27 @@ use {
pub const DEFAULT_CAPACITY_POW2: u8 = 5;
/// A Header UID of 0 indicates that the header is unlocked
const UID_UNLOCKED: Uid = 0;
pub(crate) const UID_UNLOCKED: Uid = 0;
pub(crate) type Uid = u64;
#[repr(C)]
struct Header {
lock: u64,
lock: AtomicU64,
}
impl Header {
/// try to lock this entry with 'uid'
/// return true if it could be locked
fn try_lock(&mut self, uid: Uid) -> bool {
if self.lock == UID_UNLOCKED {
self.lock = uid;
true
} else {
false
}
fn try_lock(&self, uid: Uid) -> bool {
Ok(UID_UNLOCKED)
== self
.lock
.compare_exchange(UID_UNLOCKED, uid, Ordering::AcqRel, Ordering::Relaxed)
}
/// mark this entry as unlocked
fn unlock(&mut self, expected: Uid) {
assert_eq!(expected, self.lock);
self.lock = UID_UNLOCKED;
fn unlock(&self) -> Uid {
self.lock.swap(UID_UNLOCKED, Ordering::Release)
}
/// uid that has locked this entry or None if unlocked
fn uid(&self) -> Option<Uid> {
if self.lock == UID_UNLOCKED {
None
} else {
Some(self.lock)
}
}
/// true if this entry is unlocked
fn is_unlocked(&self) -> bool {
self.lock == UID_UNLOCKED
fn uid(&self) -> Uid {
self.lock.load(Ordering::Acquire)
}
}
@@ -79,7 +64,7 @@ pub struct BucketStorage {
mmap: MmapMut,
pub cell_size: u64,
pub capacity_pow2: u8,
pub count: Arc<AtomicU64>,
pub used: AtomicU64,
pub stats: Arc<BucketStats>,
pub max_search: MaxSearch,
}
@@ -103,7 +88,6 @@ impl BucketStorage {
capacity_pow2: u8,
max_search: MaxSearch,
stats: Arc<BucketStats>,
count: Arc<AtomicU64>,
) -> Self {
let cell_size = elem_size * num_elems + std::mem::size_of::<Header>() as u64;
let (mmap, path) = Self::new_map(&drives, cell_size as usize, capacity_pow2, &stats);
@@ -111,7 +95,7 @@ impl BucketStorage {
path,
mmap,
cell_size,
count,
used: AtomicU64::new(0),
capacity_pow2,
stats,
max_search,
@@ -128,7 +112,6 @@ impl BucketStorage {
elem_size: u64,
max_search: MaxSearch,
stats: Arc<BucketStats>,
count: Arc<AtomicU64>,
) -> Self {
Self::new_with_capacity(
drives,
@@ -137,74 +120,53 @@ impl BucketStorage {
DEFAULT_CAPACITY_POW2,
max_search,
stats,
count,
)
}
/// return ref to header of item 'ix' in mmapped file
fn header_ptr(&self, ix: u64) -> &Header {
pub fn uid(&self, ix: u64) -> Uid {
assert!(ix < self.capacity(), "bad index size");
let ix = (ix * self.cell_size) as usize;
let hdr_slice: &[u8] = &self.mmap[ix..ix + std::mem::size_of::<Header>()];
unsafe {
let hdr = hdr_slice.as_ptr() as *const Header;
hdr.as_ref().unwrap()
return hdr.as_ref().unwrap().uid();
}
}
/// return ref to header of item 'ix' in mmapped file
fn header_mut_ptr(&mut self, ix: u64) -> &mut Header {
let ix = (ix * self.cell_size) as usize;
let hdr_slice: &mut [u8] = &mut self.mmap[ix..ix + std::mem::size_of::<Header>()];
unsafe {
let hdr = hdr_slice.as_mut_ptr() as *mut Header;
hdr.as_mut().unwrap()
}
}
/// return uid allocated at index 'ix' or None if vacant
pub fn uid(&self, ix: u64) -> Option<Uid> {
assert!(ix < self.capacity(), "bad index size");
self.header_ptr(ix).uid()
}
/// true if the entry at index 'ix' is free (as opposed to being allocated)
pub fn is_free(&self, ix: u64) -> bool {
// note that the terminology in the implementation is locked or unlocked.
// but our api is allocate/free
self.header_ptr(ix).is_unlocked()
}
/// caller knows id is not empty
pub fn uid_unchecked(&self, ix: u64) -> Uid {
self.uid(ix).unwrap()
}
/// 'is_resizing' true if caller is resizing the index (so don't increment count)
/// 'is_resizing' false if caller is adding an item to the index (so increment count)
pub fn allocate(
&mut self,
ix: u64,
uid: Uid,
is_resizing: bool,
) -> Result<(), BucketStorageError> {
pub fn allocate(&self, ix: u64, uid: Uid) -> Result<(), BucketStorageError> {
assert!(ix < self.capacity(), "allocate: bad index size");
assert!(UID_UNLOCKED != uid, "allocate: bad uid");
let mut e = Err(BucketStorageError::AlreadyAllocated);
let ix = (ix * self.cell_size) as usize;
//debug!("ALLOC {} {}", ix, uid);
if self.header_mut_ptr(ix).try_lock(uid) {
e = Ok(());
if !is_resizing {
self.count.fetch_add(1, Ordering::Relaxed);
let hdr_slice: &[u8] = &self.mmap[ix..ix + std::mem::size_of::<Header>()];
unsafe {
let hdr = hdr_slice.as_ptr() as *const Header;
if hdr.as_ref().unwrap().try_lock(uid) {
e = Ok(());
self.used.fetch_add(1, Ordering::Relaxed);
}
}
};
e
}
pub fn free(&mut self, ix: u64, uid: Uid) {
pub fn free(&self, ix: u64, uid: Uid) {
assert!(ix < self.capacity(), "bad index size");
assert!(UID_UNLOCKED != uid, "free: bad uid");
self.header_mut_ptr(ix).unlock(uid);
self.count.fetch_sub(1, Ordering::Relaxed);
let ix = (ix * self.cell_size) as usize;
//debug!("FREE {} {}", ix, uid);
let hdr_slice: &[u8] = &self.mmap[ix..ix + std::mem::size_of::<Header>()];
unsafe {
let hdr = hdr_slice.as_ptr() as *const Header;
//debug!("FREE uid: {}", hdr.as_ref().unwrap().uid());
let previous_uid = hdr.as_ref().unwrap().unlock();
assert_eq!(
previous_uid, uid,
"free: unlocked a header with a differet uid: {}",
previous_uid
);
self.used.fetch_sub(1, Ordering::Relaxed);
}
}
pub fn get<T: Sized>(&self, ix: u64) -> &T {
@@ -362,9 +324,6 @@ impl BucketStorage {
capacity_pow_2,
max_search,
Arc::clone(stats),
bucket
.map(|bucket| Arc::clone(&bucket.count))
.unwrap_or_default(),
);
if let Some(bucket) = bucket {
new_bucket.copy_contents(bucket);
@@ -382,43 +341,3 @@ impl BucketStorage {
1 << self.capacity_pow2
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_bucket_storage() {
let tmpdir1 = std::env::temp_dir().join("bucket_map_test_mt");
let paths: Vec<PathBuf> = [tmpdir1]
.iter()
.filter(|x| std::fs::create_dir_all(x).is_ok())
.cloned()
.collect();
assert!(!paths.is_empty());
let mut storage =
BucketStorage::new(Arc::new(paths), 1, 1, 1, Arc::default(), Arc::default());
let ix = 0;
let uid = Uid::MAX;
assert!(storage.is_free(ix));
assert!(storage.allocate(ix, uid, false).is_ok());
assert!(storage.allocate(ix, uid, false).is_err());
assert!(!storage.is_free(ix));
assert_eq!(storage.uid(ix), Some(uid));
assert_eq!(storage.uid_unchecked(ix), uid);
storage.free(ix, uid);
assert!(storage.is_free(ix));
assert_eq!(storage.uid(ix), None);
let uid = 1;
assert!(storage.is_free(ix));
assert!(storage.allocate(ix, uid, false).is_ok());
assert!(storage.allocate(ix, uid, false).is_err());
assert!(!storage.is_free(ix));
assert_eq!(storage.uid(ix), Some(uid));
assert_eq!(storage.uid_unchecked(ix), uid);
storage.free(ix, uid);
assert!(storage.is_free(ix));
assert_eq!(storage.uid(ix), None);
}
}

View File

@@ -1,12 +1,9 @@
#![allow(dead_code)]
use {
crate::{
bucket::Bucket,
bucket_storage::{BucketStorage, Uid},
RefCount,
},
modular_bitfield::prelude::*,
solana_sdk::{clock::Slot, pubkey::Pubkey},
std::{
collections::hash_map::DefaultHasher,
@@ -22,54 +19,15 @@ use {
pub struct IndexEntry {
pub key: Pubkey, // can this be smaller if we have reduced the keys into buckets already?
pub ref_count: RefCount, // can this be smaller? Do we ever need more than 4B refcounts?
storage_cap_and_offset: PackedStorage,
pub storage_offset: u64, // smaller? since these are variably sized, this could get tricky. well, actually accountinfo is not variable sized...
// if the bucket doubled, the index can be recomputed using create_bucket_capacity_pow2
pub storage_capacity_when_created_pow2: u8, // see data_location
pub num_slots: Slot, // can this be smaller? epoch size should ~ be the max len. this is the num elements in the slot list
}
/// Pack the storage offset and capacity-when-crated-pow2 fields into a single u64
#[bitfield(bits = 64)]
#[repr(C)]
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
struct PackedStorage {
capacity_when_created_pow2: B8,
offset: B56,
}
impl IndexEntry {
pub fn init(&mut self, pubkey: &Pubkey) {
self.key = *pubkey;
self.ref_count = 0;
self.storage_cap_and_offset = PackedStorage::default();
self.num_slots = 0;
}
pub fn set_storage_capacity_when_created_pow2(
&mut self,
storage_capacity_when_created_pow2: u8,
) {
self.storage_cap_and_offset
.set_capacity_when_created_pow2(storage_capacity_when_created_pow2)
}
pub fn set_storage_offset(&mut self, storage_offset: u64) {
self.storage_cap_and_offset
.set_offset_checked(storage_offset)
.expect("New storage offset must fit into 7 bytes!")
}
/// return closest bucket index fit for the slot slice.
/// Since bucket size is 2^index, the return value is
/// min index, such that 2^index >= num_slots
/// index = ceiling(log2(num_slots))
/// special case, when slot slice empty, return 0th index.
pub fn data_bucket_from_num_slots(num_slots: Slot) -> u64 {
// Compute the ceiling of log2 for integer
if num_slots == 0 {
0
} else {
(Slot::BITS - (num_slots - 1).leading_zeros()) as u64
}
(num_slots as f64).log2().ceil() as u64 // use int log here?
}
pub fn data_bucket_ix(&self) -> u64 {
@@ -80,18 +38,10 @@ impl IndexEntry {
self.ref_count
}
fn storage_capacity_when_created_pow2(&self) -> u8 {
self.storage_cap_and_offset.capacity_when_created_pow2()
}
fn storage_offset(&self) -> u64 {
self.storage_cap_and_offset.offset()
}
// This function maps the original data location into an index in the current bucket storage.
// This is coupled with how we resize bucket storages.
pub fn data_loc(&self, storage: &BucketStorage) -> u64 {
self.storage_offset() << (storage.capacity_pow2 - self.storage_capacity_when_created_pow2())
self.storage_offset << (storage.capacity_pow2 - self.storage_capacity_when_created_pow2)
}
pub fn read_value<'a, T>(&self, bucket: &'a Bucket<T>) -> Option<(&'a [T], RefCount)> {
@@ -100,7 +50,7 @@ impl IndexEntry {
let slice = if self.num_slots > 0 {
let loc = self.data_loc(data_bucket);
let uid = Self::key_uid(&self.key);
assert_eq!(Some(uid), bucket.data[data_bucket_ix as usize].uid(loc));
assert_eq!(uid, bucket.data[data_bucket_ix as usize].uid(loc));
bucket.data[data_bucket_ix as usize].get_cell_slice(loc, self.num_slots)
} else {
// num_slots is 0. This means we don't have an actual allocation.
@@ -109,78 +59,9 @@ impl IndexEntry {
};
Some((slice, self.ref_count))
}
pub fn key_uid(key: &Pubkey) -> Uid {
let mut s = DefaultHasher::new();
key.hash(&mut s);
s.finish().max(1u64)
}
}
#[cfg(test)]
mod tests {
use super::*;
impl IndexEntry {
pub fn new(key: Pubkey) -> Self {
IndexEntry {
key,
ref_count: 0,
storage_cap_and_offset: PackedStorage::default(),
num_slots: 0,
}
}
}
/// verify that accessors for storage_offset and capacity_when_created are
/// correct and independent
#[test]
fn test_api() {
for offset in [0, 1, u32::MAX as u64] {
let mut index = IndexEntry::new(solana_sdk::pubkey::new_rand());
if offset != 0 {
index.set_storage_offset(offset);
}
assert_eq!(index.storage_offset(), offset);
assert_eq!(index.storage_capacity_when_created_pow2(), 0);
for pow in [1, 255, 0] {
index.set_storage_capacity_when_created_pow2(pow);
assert_eq!(index.storage_offset(), offset);
assert_eq!(index.storage_capacity_when_created_pow2(), pow);
}
}
}
#[test]
fn test_size() {
assert_eq!(std::mem::size_of::<PackedStorage>(), 1 + 7);
assert_eq!(std::mem::size_of::<IndexEntry>(), 32 + 8 + 8 + 8);
}
#[test]
#[should_panic(expected = "New storage offset must fit into 7 bytes!")]
fn test_set_storage_offset_value_too_large() {
let too_big = 1 << 56;
let mut index = IndexEntry::new(Pubkey::new_unique());
index.set_storage_offset(too_big);
}
#[test]
fn test_data_bucket_from_num_slots() {
for n in 0..512 {
assert_eq!(
IndexEntry::data_bucket_from_num_slots(n),
(n as f64).log2().ceil() as u64
);
}
assert_eq!(IndexEntry::data_bucket_from_num_slots(u32::MAX as u64), 32);
assert_eq!(
IndexEntry::data_bucket_from_num_slots(u32::MAX as u64 + 1),
32
);
assert_eq!(
IndexEntry::data_bucket_from_num_slots(u32::MAX as u64 + 2),
33
);
}
}

View File

@@ -1,365 +0,0 @@
#!/usr/bin/env bash
#
# Builds a buildkite pipeline based on the environment variables
#
set -e
cd "$(dirname "$0")"/..
output_file=${1:-/dev/stderr}
if [[ -n $CI_PULL_REQUEST ]]; then
IFS=':' read -ra affected_files <<< "$(buildkite-agent meta-data get affected_files)"
if [[ ${#affected_files[*]} -eq 0 ]]; then
echo "Unable to determine the files affected by this PR"
exit 1
fi
else
affected_files=()
fi
annotate() {
if [[ -n $BUILDKITE ]]; then
buildkite-agent annotate "$@"
fi
}
# Checks if a CI pull request affects one or more path patterns. Each
# pattern argument is checked in series. If one of them found to be affected,
# return immediately as such.
#
# Bash regular expressions are permitted in the pattern:
# affects .rs$ -- any file or directory ending in .rs
# affects .rs -- also matches foo.rs.bar
# affects ^snap/ -- anything under the snap/ subdirectory
# affects snap/ -- also matches foo/snap/
# Any pattern starting with the ! character will be negated:
# affects !^docs/ -- anything *not* under the docs/ subdirectory
#
affects() {
if [[ -z $CI_PULL_REQUEST ]]; then
# affected_files metadata is not currently available for non-PR builds so assume
# the worse (affected)
return 0
fi
# Assume everyting needs to be tested when any Dockerfile changes
for pattern in ^ci/docker-rust/Dockerfile ^ci/docker-rust-nightly/Dockerfile "$@"; do
if [[ ${pattern:0:1} = "!" ]]; then
for file in "${affected_files[@]}"; do
if [[ ! $file =~ ${pattern:1} ]]; then
return 0 # affected
fi
done
else
for file in "${affected_files[@]}"; do
if [[ $file =~ $pattern ]]; then
return 0 # affected
fi
done
fi
done
return 1 # not affected
}
# Checks if a CI pull request affects anything other than the provided path patterns
#
# Syntax is the same as `affects()` except that the negation prefix is not
# supported
#
affects_other_than() {
if [[ -z $CI_PULL_REQUEST ]]; then
# affected_files metadata is not currently available for non-PR builds so assume
# the worse (affected)
return 0
fi
for file in "${affected_files[@]}"; do
declare matched=false
for pattern in "$@"; do
if [[ $file =~ $pattern ]]; then
matched=true
fi
done
if ! $matched; then
return 0 # affected
fi
done
return 1 # not affected
}
start_pipeline() {
echo "# $*" > "$output_file"
echo "steps:" >> "$output_file"
}
command_step() {
cat >> "$output_file" <<EOF
- name: "$1"
command: "$2"
timeout_in_minutes: $3
artifact_paths: "log-*.txt"
EOF
}
trigger_secondary_step() {
cat >> "$output_file" <<"EOF"
- trigger: "solana-secondary"
branches: "!pull/*"
async: true
build:
message: "${BUILDKITE_MESSAGE}"
commit: "${BUILDKITE_COMMIT}"
branch: "${BUILDKITE_BRANCH}"
env:
TRIGGERED_BUILDKITE_TAG: "${BUILDKITE_TAG}"
EOF
}
wait_step() {
echo " - wait" >> "$output_file"
}
all_test_steps() {
command_step checks ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_nightly_docker_image ci/test-checks.sh" 20
wait_step
# Coverage...
if affects \
.rs$ \
Cargo.lock$ \
Cargo.toml$ \
^ci/rust-version.sh \
^ci/test-coverage.sh \
^scripts/coverage.sh \
; then
command_step coverage ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_nightly_docker_image ci/test-coverage.sh" 50
wait_step
else
annotate --style info --context test-coverage \
"Coverage skipped as no .rs files were modified"
fi
# Coverage in disk...
if affects \
.rs$ \
Cargo.lock$ \
Cargo.toml$ \
^ci/rust-version.sh \
^ci/test-coverage.sh \
^scripts/coverage-in-disk.sh \
; then
command_step coverage-in-disk ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_nightly_docker_image ci/test-coverage.sh" 50
wait_step
else
annotate --style info --context test-coverage \
"Coverage skipped as no .rs files were modified"
fi
# Full test suite
command_step stable ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_stable_docker_image ci/test-stable.sh" 70
wait_step
# BPF test suite
if affects \
.rs$ \
Cargo.lock$ \
Cargo.toml$ \
^ci/rust-version.sh \
^ci/test-stable-bpf.sh \
^ci/test-stable.sh \
^ci/test-local-cluster.sh \
^core/build.rs \
^fetch-perf-libs.sh \
^programs/ \
^sdk/ \
; then
cat >> "$output_file" <<"EOF"
- command: "ci/test-stable-bpf.sh"
name: "stable-bpf"
timeout_in_minutes: 20
artifact_paths: "bpf-dumps.tar.bz2"
agents:
- "queue=default"
EOF
else
annotate --style info \
"Stable-BPF skipped as no relevant files were modified"
fi
# Perf test suite
if affects \
.rs$ \
Cargo.lock$ \
Cargo.toml$ \
^ci/rust-version.sh \
^ci/test-stable-perf.sh \
^ci/test-stable.sh \
^ci/test-local-cluster.sh \
^core/build.rs \
^fetch-perf-libs.sh \
^programs/ \
^sdk/ \
; then
cat >> "$output_file" <<"EOF"
- command: "ci/test-stable-perf.sh"
name: "stable-perf"
timeout_in_minutes: 20
artifact_paths: "log-*.txt"
agents:
- "queue=cuda"
EOF
else
annotate --style info \
"Stable-perf skipped as no relevant files were modified"
fi
# Downstream backwards compatibility
if affects \
.rs$ \
Cargo.lock$ \
Cargo.toml$ \
^ci/rust-version.sh \
^ci/test-stable-perf.sh \
^ci/test-stable.sh \
^ci/test-local-cluster.sh \
^core/build.rs \
^fetch-perf-libs.sh \
^programs/ \
^sdk/ \
^scripts/build-downstream-projects.sh \
; then
cat >> "$output_file" <<"EOF"
- command: "scripts/build-downstream-projects.sh"
name: "downstream-projects"
timeout_in_minutes: 30
EOF
else
annotate --style info \
"downstream-projects skipped as no relevant files were modified"
fi
# Downstream Anchor projects backwards compatibility
if affects \
.rs$ \
Cargo.lock$ \
Cargo.toml$ \
^ci/rust-version.sh \
^ci/test-stable-perf.sh \
^ci/test-stable.sh \
^ci/test-local-cluster.sh \
^core/build.rs \
^fetch-perf-libs.sh \
^programs/ \
^sdk/ \
^scripts/build-downstream-anchor-projects.sh \
; then
cat >> "$output_file" <<"EOF"
- command: "scripts/build-downstream-anchor-projects.sh"
name: "downstream-anchor-projects"
timeout_in_minutes: 10
EOF
else
annotate --style info \
"downstream-anchor-projects skipped as no relevant files were modified"
fi
# Wasm support
if affects \
^ci/test-wasm.sh \
^ci/test-stable.sh \
^sdk/ \
; then
command_step wasm ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_stable_docker_image ci/test-wasm.sh" 20
else
annotate --style info \
"wasm skipped as no relevant files were modified"
fi
# Benches...
if affects \
.rs$ \
Cargo.lock$ \
Cargo.toml$ \
^ci/rust-version.sh \
^ci/test-coverage.sh \
^ci/test-bench.sh \
; then
command_step bench "ci/test-bench.sh" 30
else
annotate --style info --context test-bench \
"Bench skipped as no .rs files were modified"
fi
command_step "local-cluster" \
". ci/rust-version.sh; ci/docker-run.sh \$\$rust_stable_docker_image ci/test-local-cluster.sh" \
40
command_step "local-cluster-flakey" \
". ci/rust-version.sh; ci/docker-run.sh \$\$rust_stable_docker_image ci/test-local-cluster-flakey.sh" \
10
command_step "local-cluster-slow" \
". ci/rust-version.sh; ci/docker-run.sh \$\$rust_stable_docker_image ci/test-local-cluster-slow.sh" \
40
}
pull_or_push_steps() {
command_step sanity "ci/test-sanity.sh" 5
wait_step
# Check for any .sh file changes
if affects .sh$; then
command_step shellcheck "ci/shellcheck.sh" 5
wait_step
fi
# Run the full test suite by default, skipping only if modifications are local
# to some particular areas of the tree
if affects_other_than ^.buildkite ^.mergify .md$ ^docs/ ^web3.js/ ^explorer/ ^.gitbook; then
all_test_steps
fi
# web3.js, explorer and docs changes run on Travis or Github actions...
}
if [[ -n $BUILDKITE_TAG ]]; then
start_pipeline "Tag pipeline for $BUILDKITE_TAG"
annotate --style info --context release-tag \
"https://github.com/solana-labs/solana/releases/$BUILDKITE_TAG"
# Jump directly to the secondary build to publish release artifacts quickly
trigger_secondary_step
exit 0
fi
if [[ $BUILDKITE_BRANCH =~ ^pull ]]; then
echo "+++ Affected files in this PR"
for file in "${affected_files[@]}"; do
echo "- $file"
done
start_pipeline "Pull request pipeline for $BUILDKITE_BRANCH"
# Add helpful link back to the corresponding Github Pull Request
annotate --style info --context pr-backlink \
"Github Pull Request: https://github.com/solana-labs/solana/$BUILDKITE_BRANCH"
if [[ $GITHUB_USER = "dependabot[bot]" ]]; then
command_step dependabot "ci/dependabot-pr.sh" 5
wait_step
fi
pull_or_push_steps
exit 0
fi
start_pipeline "Push pipeline for ${BUILDKITE_BRANCH:-?unknown branch?}"
pull_or_push_steps
wait_step
trigger_secondary_step
exit 0

View File

@@ -102,8 +102,6 @@ command_step() {
command: "$2"
timeout_in_minutes: $3
artifact_paths: "log-*.txt"
agents:
- "queue=solana"
EOF
}
@@ -139,7 +137,7 @@ all_test_steps() {
^ci/test-coverage.sh \
^scripts/coverage.sh \
; then
command_step coverage ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_nightly_docker_image ci/test-coverage.sh" 50
command_step coverage ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_nightly_docker_image ci/test-coverage.sh" 40
wait_step
else
annotate --style info --context test-coverage \
@@ -147,7 +145,7 @@ all_test_steps() {
fi
# Full test suite
command_step stable ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_stable_docker_image ci/test-stable.sh" 70
command_step stable ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_stable_docker_image ci/test-stable.sh" 60
wait_step
# BPF test suite
@@ -170,7 +168,7 @@ all_test_steps() {
timeout_in_minutes: 20
artifact_paths: "bpf-dumps.tar.bz2"
agents:
- "queue=solana"
- "queue=default"
EOF
else
annotate --style info \
@@ -223,41 +221,12 @@ EOF
- command: "scripts/build-downstream-projects.sh"
name: "downstream-projects"
timeout_in_minutes: 30
agents:
- "queue=solana"
EOF
else
annotate --style info \
"downstream-projects skipped as no relevant files were modified"
fi
# Downstream Anchor projects backwards compatibility
if affects \
.rs$ \
Cargo.lock$ \
Cargo.toml$ \
^ci/rust-version.sh \
^ci/test-stable-perf.sh \
^ci/test-stable.sh \
^ci/test-local-cluster.sh \
^core/build.rs \
^fetch-perf-libs.sh \
^programs/ \
^sdk/ \
^scripts/build-downstream-anchor-projects.sh \
; then
cat >> "$output_file" <<"EOF"
- command: "scripts/build-downstream-anchor-projects.sh"
name: "downstream-anchor-projects"
timeout_in_minutes: 10
agents:
- "queue=solana"
EOF
else
annotate --style info \
"downstream-anchor-projects skipped as no relevant files were modified"
fi
# Wasm support
if affects \
^ci/test-wasm.sh \
@@ -295,7 +264,7 @@ EOF
command_step "local-cluster-slow" \
". ci/rust-version.sh; ci/docker-run.sh \$\$rust_stable_docker_image ci/test-local-cluster-slow.sh" \
40
30
}
pull_or_push_steps() {

View File

@@ -8,6 +8,11 @@ src_root="$(readlink -f "${here}/..")"
cd "${src_root}"
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
@@ -25,10 +30,22 @@ cargo_audit_ignores=(
# generic-array: arr! macro erases lifetimes
#
# Blocked on new spl dependencies on solana-program v1.9
# due to curve25519-dalek dependency
# Blocked on libsecp256k1 releasing with upgraded dependencies
# https://github.com/paritytech/libsecp256k1/issues/66
--ignore RUSTSEC-2020-0146
# hyper: Lenient `hyper` header parsing of `Content-Length` could allow request smuggling
#
# Blocked on jsonrpc removing dependency on unmaintained `websocket`
# https://github.com/paritytech/jsonrpc/issues/605
--ignore RUSTSEC-2021-0078
# hyper: Integer overflow in `hyper`'s parsing of the `Transfer-Encoding` header leads to data loss
#
# Blocked on jsonrpc removing dependency on unmaintained `websocket`
# https://github.com/paritytech/jsonrpc/issues/605
--ignore RUSTSEC-2021-0079
# chrono: Potential segfault in `localtime_r` invocations
#
# Blocked due to no safe upgrade

View File

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

View File

@@ -3,14 +3,8 @@ set -ex
cd "$(dirname "$0")"
platform=()
if [[ $(uname -m) = arm64 ]]; then
# Ref: https://blog.jaimyn.dev/how-to-build-multi-architecture-docker-images-on-an-m1-mac/#tldr
platform+=(--platform linux/amd64)
fi
nightlyDate=${1:-$(date +%Y-%m-%d)}
docker build "${platform[@]}" -t solanalabs/rust-nightly:"$nightlyDate" --build-arg date="$nightlyDate" .
docker build -t solanalabs/rust-nightly:"$nightlyDate" --build-arg date="$nightlyDate" .
maybeEcho=
if [[ -z $CI ]]; then

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

View File

@@ -3,14 +3,7 @@ set -ex
cd "$(dirname "$0")"
platform=()
if [[ $(uname -m) = arm64 ]]; then
# Ref: https://blog.jaimyn.dev/how-to-build-multi-architecture-docker-images-on-an-m1-mac/#tldr
platform+=(--platform linux/amd64)
fi
docker build "${platform[@]}" -t solanalabs/rust .
docker build -t solanalabs/rust .
read -r rustc version _ < <(docker run solanalabs/rust rustc --version)
[[ $rustc = rustc ]]

View File

@@ -70,7 +70,7 @@ for Cargo_toml in $Cargo_tomls; do
rm -rf crate-test
"$cargo" stable init crate-test
cd crate-test/
echo "${crate_name} = \"=${expectedCrateVersion}\"" >> Cargo.toml
echo "${crate_name} = \"${expectedCrateVersion}\"" >> Cargo.toml
echo "[workspace]" >> Cargo.toml
"$cargo" stable check
) && really_uploaded=1

View File

@@ -150,7 +150,7 @@ elif [[ -n $BUILDKITE ]]; then
cat > release.solana.com-install <<EOF
SOLANA_RELEASE=$CHANNEL_OR_TAG
SOLANA_INSTALL_INIT_ARGS=$CHANNEL_OR_TAG
SOLANA_DOWNLOAD_ROOT=https://release.solana.com
SOLANA_DOWNLOAD_ROOT=http://release.solana.com
EOF
cat install/solana-install-init.sh >> release.solana.com-install

View File

@@ -7,7 +7,7 @@ source multinode-demo/common.sh
rm -rf config/run/init-completed config/ledger config/snapshot-ledger
SOLANA_RUN_SH_VALIDATOR_ARGS="--full-snapshot-interval-slots 200" timeout 120 ./scripts/run.sh &
SOLANA_RUN_SH_VALIDATOR_ARGS="--snapshot-interval-slots 200" timeout 120 ./scripts/run.sh &
pid=$!
attempts=20

View File

@@ -18,13 +18,13 @@
if [[ -n $RUST_STABLE_VERSION ]]; then
stable_version="$RUST_STABLE_VERSION"
else
stable_version=1.60.0
stable_version=1.57.0
fi
if [[ -n $RUST_NIGHTLY_VERSION ]]; then
nightly_version="$RUST_NIGHTLY_VERSION"
else
nightly_version=2022-04-01
nightly_version=2021-12-03
fi

View File

@@ -1,24 +0,0 @@
#!/usr/bin/env bash
#
# Finds the version of sbf-tools used by this source tree.
#
# stdout of this script may be eval-ed.
#
here="$(dirname "$0")"
SBF_TOOLS_VERSION=unknown
cargo_build_bpf_main="${here}/../sdk/cargo-build-bpf/src/main.rs"
if [[ -f "${cargo_build_bpf_main}" ]]; then
version=$(sed -e 's/^.*bpf_tools_version\s*=\s*"\(v[0-9.]\+\)".*/\1/;t;d' "${cargo_build_bpf_main}")
if [[ ${version} != '' ]]; then
SBF_TOOLS_VERSION="${version}"
else
echo '--- unable to parse SBF_TOOLS_VERSION'
fi
else
echo "--- '${cargo_build_bpf_main}' not present"
fi
echo SBF_TOOLS_VERSION="${SBF_TOOLS_VERSION}"

View File

@@ -57,20 +57,32 @@ if [[ $CI_BASE_BRANCH = "$EDGE_CHANNEL" ]]; then
exit "$check_status"
fi
# Ensure nightly and --benches
# Ensure nightly and --benches
_ scripts/cargo-for-all-lock-files.sh nightly check --locked --all-targets
else
echo "Note: cargo-for-all-lock-files.sh skipped because $CI_BASE_BRANCH != $EDGE_CHANNEL"
fi
_ ci/order-crates-for-publishing.py
_ ci/order-crates-for-publishing.py
# -Z... is needed because of clippy bug: https://github.com/rust-lang/rust-clippy/issues/4612
# run nightly clippy for `sdk/` as there's a moderate amount of nightly-only code there
_ scripts/cargo-for-all-lock-files.sh -- nightly clippy -Zunstable-options --all-targets -- --deny=warnings --deny=clippy::integer_arithmetic
_ "$cargo" nightly clippy -Zunstable-options --workspace --all-targets -- --deny=warnings --deny=clippy::integer_arithmetic
_ scripts/cargo-for-all-lock-files.sh -- nightly fmt --all -- --check
_ "$cargo" stable fmt --all -- --check
_ ci/do-audit.sh
_ ci/do-audit.sh
{
cd programs/bpf
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
)
done
}
echo --- ok

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