Compare commits
539 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
e012a05b08 | ||
|
aa5e23799f | ||
|
44dbc51f8c | ||
|
f20280620a | ||
|
b9b81def35 | ||
|
972d101f6e | ||
|
b2f7be0351 | ||
|
be43512bae | ||
|
5df386ae0e | ||
|
c5d174c170 | ||
|
9b6ec0b6d5 | ||
|
1a88a9eb0e | ||
|
66a9e6bcb4 | ||
|
2d0c0bc8ba | ||
|
2b6962c063 | ||
|
ed37cfed1c | ||
|
8f1a08e15c | ||
|
c8d9e6c8c8 | ||
|
3a1b2c8c9e | ||
|
77e6cd35ee | ||
|
6c390aeb67 | ||
|
cde248ae73 | ||
|
9bc20a8cbb | ||
|
6fd959c6d2 | ||
|
94e50b61e8 | ||
|
4113acbf24 | ||
|
572c0af699 | ||
|
0a3bf17bb5 | ||
|
431a82276e | ||
|
14505f5bfd | ||
|
c17c74021c | ||
|
cfc0e2d61f | ||
|
b7fc704092 | ||
|
8bf5cdb349 | ||
|
eaa6aa0998 | ||
|
3b3822846b | ||
|
da7185e2ed | ||
|
ccef24c44e | ||
|
0c6a133b63 | ||
|
7873f6fb30 | ||
|
7cba9b8f8f | ||
|
ca55bce522 | ||
|
7de8a55b54 | ||
|
7232b01a02 | ||
|
a4ebbc9f55 | ||
|
bf7c2f79c1 | ||
|
d401c3f5ab | ||
|
83d08223fd | ||
|
6bb63f9abf | ||
|
d8293abc64 | ||
|
4d074a6716 | ||
|
3eee222667 | ||
|
a78c3c07f2 | ||
|
53f8e58300 | ||
|
b4fdce9443 | ||
|
39fe52fc06 | ||
|
db65b4e641 | ||
|
fe1c20c689 | ||
|
6566a0f6c8 | ||
|
3606de56f7 | ||
|
9a005855dc | ||
|
70bdcf06b4 | ||
|
f53f273585 | ||
|
e0584b77c5 | ||
|
39a5431790 | ||
|
715c5e64c4 | ||
|
7956f04fa5 | ||
|
2825f82bee | ||
|
45e3cd373b | ||
|
2b4b260c71 | ||
|
866fd22fde | ||
|
d23df85410 | ||
|
839cdecfd2 | ||
|
cc6296b1fa | ||
|
0c2a85a903 | ||
|
011fe72aa2 | ||
|
40fc14471d | ||
|
7fc85b8c9b | ||
|
4d77ac1688 | ||
|
77bdb45d4a | ||
|
3539849a7f | ||
|
8c28f9b63e | ||
|
3346843a87 | ||
|
007c49ff2b | ||
|
bbd386884d | ||
|
ba8426e0fd | ||
|
1017c4851a | ||
|
d7b381c90c | ||
|
870a7e8458 | ||
|
6f661dd8a9 | ||
|
2e6d03c41f | ||
|
3dbdaa5341 | ||
|
8f3ce5fc57 | ||
|
49ac17a595 | ||
|
63d7fdb4bd | ||
|
e15721f22d | ||
|
17177a41c7 | ||
|
84f0234151 | ||
|
b629291848 | ||
|
240895d387 | ||
|
50d510e4c7 | ||
|
868e757d9d | ||
|
92b2b8dae7 | ||
|
a53fe7b779 | ||
|
a9d6b90e9a | ||
|
88c5d6b10c | ||
|
9891cc6a17 | ||
|
d18a08471e | ||
|
50393adadd | ||
|
1be989c5d2 | ||
|
6bc914989b | ||
|
9a7ea1229b | ||
|
d8a2de1fd9 | ||
|
6859516126 | ||
|
57b69b5804 | ||
|
9a5a9ff633 | ||
|
06b1c980d4 | ||
|
86c26f8432 | ||
|
78d44ae215 | ||
|
31dc79a4f9 | ||
|
5c2dab8055 | ||
|
0ecd7e5c90 | ||
|
df8cf37b89 | ||
|
56a4fc3dd2 | ||
|
5380623f32 | ||
|
313e8bddd4 | ||
|
7d68c44307 | ||
|
6b9a529cda | ||
|
12eea11f93 | ||
|
d2a0445fff | ||
|
232ba8473d | ||
|
a455c8a5af | ||
|
07865a97ce | ||
|
37f618fc62 | ||
|
86ff6f82f8 | ||
|
57baf7f79b | ||
|
e259388069 | ||
|
06d6e357ae | ||
|
7759210ff3 | ||
|
16c42a7b30 | ||
|
d0f08cf25b | ||
|
0ed9f7144c | ||
|
b17c2f451a | ||
|
4aedc086e5 | ||
|
0afb330db0 | ||
|
1201ef172e | ||
|
b63a65bc21 | ||
|
392d2dbd8a | ||
|
4733d6dfc3 | ||
|
337de51088 | ||
|
24ee0b3934 | ||
|
ff8f78199d | ||
|
b524e0a1a7 | ||
|
7dcecdd285 | ||
|
151f025bee | ||
|
edc83c0543 | ||
|
b777bbf7db | ||
|
a29344e681 | ||
|
1bce8a99a2 | ||
|
3a3454d788 | ||
|
0e3131f2b4 | ||
|
27997653f1 | ||
|
c3f66dcfa7 | ||
|
6a2377dd50 | ||
|
8b1a1d9c99 | ||
|
01e2d5cd35 | ||
|
8b61ba4d8d | ||
|
f364956d15 | ||
|
cedd00e82e | ||
|
3b22f5b833 | ||
|
9c549a3ccf | ||
|
f4cf7d2c84 | ||
|
b9834ed9eb | ||
|
2781d69319 | ||
|
4d58a0e200 | ||
|
b37e5c8a36 | ||
|
b06bfeec8d | ||
|
02c4170357 | ||
|
24a21d0ba6 | ||
|
ae1687bc0a | ||
|
5d4654d2f4 | ||
|
d69c1d6db6 | ||
|
fa65107460 | ||
|
dd2d119d2b | ||
|
b7dc7d859c | ||
|
0db23fee53 | ||
|
7e073e64a3 | ||
|
7d438e5c28 | ||
|
83cc44953d | ||
|
215928445c | ||
|
de6de7a367 | ||
|
e8c054b1f4 | ||
|
df08ba5dcd | ||
|
72d038ecd8 | ||
|
b08c0caefe | ||
|
8fe5b41f5f | ||
|
25333abd96 | ||
|
f09a100e60 | ||
|
7cc96dc20f | ||
|
40c95dde4f | ||
|
0d38f11998 | ||
|
3e89cb6b43 | ||
|
5025c7c983 | ||
|
c3fafda981 | ||
|
3f6964d264 | ||
|
b1d294de75 | ||
|
2b34800870 | ||
|
e9c3e0b0ee | ||
|
0e9fe0847f | ||
|
d2e98cb531 | ||
|
32681e2739 | ||
|
dc0b21fa83 | ||
|
c4e770e2f8 | ||
|
f80af6dc1c | ||
|
36ac9b3bb1 | ||
|
282c98a82a | ||
|
11f6c04990 | ||
|
18c4d13ab2 | ||
|
d2e907655f | ||
|
e182afa50f | ||
|
00d1cb0333 | ||
|
bab82ab632 | ||
|
b9ba312975 | ||
|
c5ff373965 | ||
|
51a2d93a0d | ||
|
409ac4dcfa | ||
|
9e42883d4b | ||
|
e41460d500 | ||
|
9aacd0f3c3 | ||
|
3f908306a3 | ||
|
8093586b78 | ||
|
a08a6d55fa | ||
|
802c5fcb00 | ||
|
8749a97b94 | ||
|
4313240b1b | ||
|
24bae00560 | ||
|
fae0a6307d | ||
|
9753f1a6ca | ||
|
8ad1554bc9 | ||
|
2367f561dc | ||
|
21d41b976b | ||
|
3303ead54d | ||
|
f91d7da5a4 | ||
|
b2dad84d05 | ||
|
a7b2939bc8 | ||
|
ea3b783b63 | ||
|
733ef4b0b8 | ||
|
0cf83887c6 | ||
|
094271be7d | ||
|
efc3c0d65f | ||
|
0300eea0d6 | ||
|
b03186e3c6 | ||
|
65e1b881f9 | ||
|
28b9e5b572 | ||
|
072e884c24 | ||
|
dc95663de7 | ||
|
a73303be22 | ||
|
330f42c375 | ||
|
5d088c7d06 | ||
|
5c9495f955 | ||
|
fb163187b5 | ||
|
970bba495f | ||
|
9761af201b | ||
|
7600be946a | ||
|
524b380a71 | ||
|
ebb5fc1285 | ||
|
4cfb3dcc7b | ||
|
e8fff4561e | ||
|
b56e66310d | ||
|
bda3bd1557 | ||
|
7723673038 | ||
|
c69e667f5e | ||
|
6157860c0a | ||
|
32fc4e3d0f | ||
|
ee0c0c4a59 | ||
|
356117819c | ||
|
834c96a374 | ||
|
2195d980a2 | ||
|
3e43b042eb | ||
|
851742e5d9 | ||
|
c6c7feb0c2 | ||
|
1fde69ef48 | ||
|
894bedcae7 | ||
|
47f15eaa03 | ||
|
b0c0739db9 | ||
|
c3dc23e84a | ||
|
cc7fc447a4 | ||
|
a401b2b4cf | ||
|
d8c66c8981 | ||
|
49a415414f | ||
|
6c540d2ada | ||
|
da62ebac1a | ||
|
25aee12502 | ||
|
d8e8528797 | ||
|
ed8c796877 | ||
|
ec750cf3eb | ||
|
4a35053fba | ||
|
9797178ad1 | ||
|
dbc58455df | ||
|
4a3f851e49 | ||
|
5a3bf5c90e | ||
|
de6ec11efc | ||
|
7aec87c086 | ||
|
eabc21c23a | ||
|
713f346211 | ||
|
a81bc0ecf8 | ||
|
a3f1580b8b | ||
|
4f20798654 | ||
|
0ecd1755a6 | ||
|
57dd8a555a | ||
|
f64cd4a75a | ||
|
2ce6c86c2a | ||
|
ff9573714b | ||
|
826111cf79 | ||
|
f31f1d0f52 | ||
|
e220f7067b | ||
|
d9726e61bc | ||
|
786fa4f22e | ||
|
5b74678e37 | ||
|
d203bd1998 | ||
|
5f5fa38d85 | ||
|
fadf1efa41 | ||
|
0269fffa5a | ||
|
50e441a9ed | ||
|
9413051053 | ||
|
13e176a633 | ||
|
9268239c75 | ||
|
e51d7af847 | ||
|
147ba1de69 | ||
|
7cc709c82a | ||
|
a2395e8730 | ||
|
ae605f8f02 | ||
|
ea2cc90215 | ||
|
e15ddbb979 | ||
|
bbd8bd2e74 | ||
|
a5794efe16 | ||
|
27095378fa | ||
|
a8836649cb | ||
|
cc81830f13 | ||
|
558a46f5d5 | ||
|
57add5366e | ||
|
5057aaddc0 | ||
|
3865219085 | ||
|
6da06654ff | ||
|
4a375acebc | ||
|
9fcd465928 | ||
|
1f8ef5e640 | ||
|
a1b0f2f681 | ||
|
f59d4f29d9 | ||
|
b379004c3b | ||
|
25491780df | ||
|
4354ad3299 | ||
|
4e94446fc3 | ||
|
d99795c000 | ||
|
fe775a9716 | ||
|
ac76a75937 | ||
|
6c1678244f | ||
|
63a9f33be1 | ||
|
c9da91cb1c | ||
|
b3488e0139 | ||
|
f3814a0478 | ||
|
5e8d8cfb49 | ||
|
ad37276d83 | ||
|
719db7eed0 | ||
|
4ddb72a32d | ||
|
ff1171338f | ||
|
28683b0ad8 | ||
|
4ef3a679a4 | ||
|
e02bcbdae2 | ||
|
7b0187a148 | ||
|
e92283c8d2 | ||
|
ef3781d4ee | ||
|
6da4bec41d | ||
|
31ed985fd0 | ||
|
cdc10712b1 | ||
|
935a836a7d | ||
|
97ba3cbeb0 | ||
|
e8ca35f9ec | ||
|
d5aae9a8af | ||
|
3bb8016a40 | ||
|
579065443a | ||
|
81d636c2bf | ||
|
6a7ce8500b | ||
|
8ee294639a | ||
|
b275f65ef1 | ||
|
37c2b68677 | ||
|
d9944c8ae3 | ||
|
6c8bbdca0a | ||
|
10e8f3ab32 | ||
|
8c0b0f235e | ||
|
ec8ba76e4d | ||
|
60fba7be75 | ||
|
24075ceeff | ||
|
f7ef1e68b0 | ||
|
723e7f11b9 | ||
|
f7211d3c07 | ||
|
6234090361 | ||
|
a001c1c8f6 | ||
|
7f62f4f621 | ||
|
8334a76e5b | ||
|
eadab5e2f0 | ||
|
8bb7b53f3b | ||
|
8c7b8e8c5d | ||
|
a2857928a4 | ||
|
f6780d72b1 | ||
|
5d003c6dab | ||
|
79ee0e06b2 | ||
|
443f132de5 | ||
|
95299e43a2 | ||
|
0cf1894ede | ||
|
f2f4f28c0b | ||
|
57da68d563 | ||
|
8d2337ccf8 | ||
|
270749185c | ||
|
6184254416 | ||
|
c8bb13b3f7 | ||
|
5da83c1491 | ||
|
b04ce80255 | ||
|
a788021181 | ||
|
553e9fb8cd | ||
|
f1bc7ec4fa | ||
|
581181e87f | ||
|
36e1f9fae8 | ||
|
f10ae394c8 | ||
|
f7905d369a | ||
|
ef079d202b | ||
|
b7efc2373c | ||
|
d3b50bc55b | ||
|
8fd3465f8a | ||
|
23b9e6eae3 | ||
|
fe1a977f9e | ||
|
5e538eff7c | ||
|
3efe4b5478 | ||
|
90e0d4fefe | ||
|
2e983fb39f | ||
|
527b20fbbd | ||
|
a0c4b4e5fc | ||
|
282315a721 | ||
|
b8198f8cc5 | ||
|
68ad2dcce1 | ||
|
e87c3421bc | ||
|
20754a7115 | ||
|
8a57ee181e | ||
|
4e6b5a9808 | ||
|
f24fbde43b | ||
|
47f60c7607 | ||
|
8b307ed409 | ||
|
cf21719a07 | ||
|
3157b464c4 | ||
|
2581db5748 | ||
|
634959b3ab | ||
|
03b21f2e9d | ||
|
cc5565b17e | ||
|
50beef0b15 | ||
|
06a54e1423 | ||
|
4d731ecd08 | ||
|
ee06789a66 | ||
|
2dabe1d706 | ||
|
3b1279a005 | ||
|
5c9f85f28d | ||
|
e12dd46ef3 | ||
|
c4fa03b478 | ||
|
9fb749deb7 | ||
|
bd48344de2 | ||
|
78e54f1d2c | ||
|
76a6576976 | ||
|
92ec1ae255 | ||
|
0d203728cc | ||
|
625773e5b8 | ||
|
a4cb1e45ae | ||
|
8aded2778e | ||
|
d940c5b1a3 | ||
|
1be045df94 | ||
|
86191911c7 | ||
|
8f852d8a6b | ||
|
68a439f8da | ||
|
e021832708 | ||
|
87b11aa187 | ||
|
7475a6f444 | ||
|
86ce650661 | ||
|
4dc5a53014 | ||
|
5e35cf3536 | ||
|
e8a8d1efb3 | ||
|
defd9238fa | ||
|
5f061dcea1 | ||
|
e6ee27a738 | ||
|
dd2d25d698 | ||
|
9096c3df02 | ||
|
9f94c2a9a0 | ||
|
34213da9f4 | ||
|
c3c4991c44 | ||
|
9d37a33dcd | ||
|
a04ca03fee | ||
|
64ce4a6203 | ||
|
7ac3c9ec76 | ||
|
7d91515e8d | ||
|
4e3f2c3d2d | ||
|
8b67ba6d3d | ||
|
c2ce68ab90 | ||
|
fe87cb1cd1 | ||
|
1c8f6a836a | ||
|
3d5ff7968e | ||
|
d6160f7744 | ||
|
5e9ce99abf | ||
|
ebd6fe7acb | ||
|
9e91a2c2fd | ||
|
899f57962a | ||
|
3176b00e57 | ||
|
08b9da8397 | ||
|
2bc21ecba2 | ||
|
5b2a65fab3 | ||
|
f5d56eabf3 | ||
|
af45efb62c | ||
|
f528cda832 | ||
|
eeef9f4e59 | ||
|
32124b59e9 | ||
|
aa9772f9c0 | ||
|
5f183bd773 | ||
|
2238e5001b | ||
|
79fa7ef55c | ||
|
07df827411 | ||
|
a259ff0e72 | ||
|
d7d3e767e7 | ||
|
6e8aa9af17 | ||
|
0236de7bc8 | ||
|
899bd1572a | ||
|
97ec4cd44e | ||
|
5500970a7e | ||
|
caea04d8d5 | ||
|
b1a90c3580 | ||
|
5bd4e38345 | ||
|
fddba08571 | ||
|
87963764fa | ||
|
b691a159dd | ||
|
5af1d48be8 | ||
|
3b3ec3313f | ||
|
be00246fb5 | ||
|
1d80ba9edf | ||
|
4bcf976ecd |
@@ -74,7 +74,7 @@ jobs:
|
||||
|
||||
language: node_js
|
||||
node_js:
|
||||
- "lts/*"
|
||||
- "node"
|
||||
|
||||
cache:
|
||||
directories:
|
||||
|
964
Cargo.lock
generated
964
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
14
Cargo.toml
14
Cargo.toml
@@ -21,7 +21,6 @@ members = [
|
||||
"perf",
|
||||
"validator",
|
||||
"genesis",
|
||||
"genesis-utils",
|
||||
"gossip",
|
||||
"install",
|
||||
"keygen",
|
||||
@@ -32,6 +31,7 @@ members = [
|
||||
"log-analyzer",
|
||||
"merkle-root-bench",
|
||||
"merkle-tree",
|
||||
"stake-o-matic",
|
||||
"storage-bigtable",
|
||||
"storage-proto",
|
||||
"streamer",
|
||||
@@ -39,20 +39,21 @@ members = [
|
||||
"metrics",
|
||||
"net-shaper",
|
||||
"notifier",
|
||||
"poh",
|
||||
"poh-bench",
|
||||
"program-test",
|
||||
"programs/secp256k1",
|
||||
"programs/bpf_loader",
|
||||
"programs/budget",
|
||||
"programs/config",
|
||||
"programs/exchange",
|
||||
"programs/failure",
|
||||
"programs/noop",
|
||||
"programs/ownable",
|
||||
"programs/secp256k1",
|
||||
"programs/stake",
|
||||
"programs/vest",
|
||||
"programs/vote",
|
||||
"remote-wallet",
|
||||
"rpc",
|
||||
"ramp-tps",
|
||||
"runtime",
|
||||
"runtime/store-tool",
|
||||
"sdk",
|
||||
@@ -76,10 +77,5 @@ exclude = [
|
||||
"programs/bpf",
|
||||
]
|
||||
|
||||
# TODO: Remove once the "simd-accel" feature from the reed-solomon-erasure
|
||||
# dependency is supported on Apple M1. v2 of the feature resolver is needed to
|
||||
# specify arch-specific features.
|
||||
resolver = "2"
|
||||
|
||||
[profile.dev]
|
||||
split-debuginfo = "unpacked"
|
||||
|
13
README.md
13
README.md
@@ -1,6 +1,6 @@
|
||||
<p align="center">
|
||||
<a href="https://solana.com">
|
||||
<img alt="Solana" src="https://i.imgur.com/IKyzQ6T.png" width="250" />
|
||||
<img alt="Solana" src="https://i.imgur.com/OMnvVEz.png" width="250" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -32,12 +32,6 @@ $ sudo apt-get update
|
||||
$ sudo apt-get install libssl-dev libudev-dev pkg-config zlib1g-dev llvm clang make
|
||||
```
|
||||
|
||||
On Mac M1s, make sure you set up your terminal & homebrew [to use](https://5balloons.info/correct-way-to-install-and-use-homebrew-on-m1-macs/) Rosetta. You can install it with:
|
||||
|
||||
```bash
|
||||
$ softwareupdate --install-rosetta
|
||||
```
|
||||
|
||||
## **2. Download the source code.**
|
||||
|
||||
```bash
|
||||
@@ -51,6 +45,11 @@ $ cd solana
|
||||
$ cargo build
|
||||
```
|
||||
|
||||
## **4. Run a minimal local cluster.**
|
||||
```bash
|
||||
$ ./run.sh
|
||||
```
|
||||
|
||||
# Testing
|
||||
|
||||
**Run the test suite:**
|
||||
|
20
SECURITY.md
20
SECURITY.md
@@ -51,27 +51,13 @@ The following components are out of scope for the bounty program
|
||||
* Attacks that require social engineering
|
||||
|
||||
Eligibility:
|
||||
* The participant submitting the bug report shall follow the process outlined within this document
|
||||
* The participant submitting the bug bounty shall follow the process outlined within this document
|
||||
* Valid exploits can be eligible even if they are not successfully executed on the cluster
|
||||
* Multiple submissions for the same class of exploit are still eligible for compensation, though may be compensated at a lower rate, however these will be assessed on a case-by-case basis
|
||||
* Participants must complete KYC and sign the participation agreement here when the registrations are open https://solana.com/validator-registration. Security exploits will still be assessed and open for submission at all times. This needs only be done prior to distribution of tokens.
|
||||
|
||||
Payment of Bug Bounties:
|
||||
* Payments for eligible bug reports are distributed monthly.
|
||||
* Bounties for all bug reports submitted in a given month are paid out in the middle of the
|
||||
following month.
|
||||
* The SOL/USD conversion rate used for payments is the market price at the end of
|
||||
the last day of the month for the month in which the bug was submitted.
|
||||
* The reference for this price is the Closing Price given by Coingecko.com on
|
||||
that date given here:
|
||||
https://www.coingecko.com/en/coins/solana/historical_data/usd#panel
|
||||
* For example, for all bugs submitted in March 2021, the SOL/USD price for bug
|
||||
payouts is the Close price on 2021-03-31 of $19.49. This applies to all bugs
|
||||
submitted in March 2021, to be paid in mid-April 2021.
|
||||
* Bug bounties are paid out in
|
||||
[stake accounts](https://solana.com/staking) with a
|
||||
[lockup](https://docs.solana.com/staking/stake-accounts#lockups)
|
||||
expiring 12 months from the last day of the month in which the bug was submitted.
|
||||
Notes:
|
||||
* All locked tokens can be staked during the lockup period
|
||||
|
||||
<a name="process"></a>
|
||||
## Incident Response Process
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-account-decoder"
|
||||
version = "1.7.14"
|
||||
version = "1.6.28"
|
||||
description = "Solana account decoder"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -19,10 +19,11 @@ lazy_static = "1.4.0"
|
||||
serde = "1.0.122"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.56"
|
||||
solana-config-program = { path = "../programs/config", version = "=1.7.14" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.14" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.7.14" }
|
||||
spl-token-v2-0 = { package = "spl-token", version = "=3.2.0", features = ["no-entrypoint"] }
|
||||
solana-config-program = { path = "../programs/config", version = "=1.6.28" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.28" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.28" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.28" }
|
||||
spl-token-v2-0 = { package = "spl-token", version = "=3.1.1", features = ["no-entrypoint"] }
|
||||
thiserror = "1.0"
|
||||
zstd = "0.5.1"
|
||||
|
||||
|
@@ -28,7 +28,6 @@ use {
|
||||
|
||||
pub type StringAmount = String;
|
||||
pub type StringDecimals = String;
|
||||
pub const MAX_BASE58_BYTES: usize = 128;
|
||||
|
||||
/// A duplicate representation of an Account for pretty JSON serialization
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
@@ -61,17 +60,6 @@ pub enum UiAccountEncoding {
|
||||
}
|
||||
|
||||
impl UiAccount {
|
||||
fn encode_bs58<T: ReadableAccount>(
|
||||
account: &T,
|
||||
data_slice_config: Option<UiDataSliceConfig>,
|
||||
) -> String {
|
||||
if account.data().len() <= MAX_BASE58_BYTES {
|
||||
bs58::encode(slice_data(account.data(), data_slice_config)).into_string()
|
||||
} else {
|
||||
"error: data too large for bs58 encoding".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encode<T: ReadableAccount>(
|
||||
pubkey: &Pubkey,
|
||||
account: &T,
|
||||
@@ -80,34 +68,33 @@ impl UiAccount {
|
||||
data_slice_config: Option<UiDataSliceConfig>,
|
||||
) -> Self {
|
||||
let data = match encoding {
|
||||
UiAccountEncoding::Binary => {
|
||||
let data = Self::encode_bs58(account, data_slice_config);
|
||||
UiAccountData::LegacyBinary(data)
|
||||
}
|
||||
UiAccountEncoding::Base58 => {
|
||||
let data = Self::encode_bs58(account, data_slice_config);
|
||||
UiAccountData::Binary(data, encoding)
|
||||
}
|
||||
UiAccountEncoding::Binary => UiAccountData::LegacyBinary(
|
||||
bs58::encode(slice_data(&account.data(), data_slice_config)).into_string(),
|
||||
),
|
||||
UiAccountEncoding::Base58 => UiAccountData::Binary(
|
||||
bs58::encode(slice_data(&account.data(), data_slice_config)).into_string(),
|
||||
encoding,
|
||||
),
|
||||
UiAccountEncoding::Base64 => UiAccountData::Binary(
|
||||
base64::encode(slice_data(account.data(), data_slice_config)),
|
||||
base64::encode(slice_data(&account.data(), data_slice_config)),
|
||||
encoding,
|
||||
),
|
||||
UiAccountEncoding::Base64Zstd => {
|
||||
let mut encoder = zstd::stream::write::Encoder::new(Vec::new(), 0).unwrap();
|
||||
match encoder
|
||||
.write_all(slice_data(account.data(), data_slice_config))
|
||||
.write_all(slice_data(&account.data(), data_slice_config))
|
||||
.and_then(|()| encoder.finish())
|
||||
{
|
||||
Ok(zstd_data) => UiAccountData::Binary(base64::encode(zstd_data), encoding),
|
||||
Err(_) => UiAccountData::Binary(
|
||||
base64::encode(slice_data(account.data(), data_slice_config)),
|
||||
base64::encode(slice_data(&account.data(), data_slice_config)),
|
||||
UiAccountEncoding::Base64,
|
||||
),
|
||||
}
|
||||
}
|
||||
UiAccountEncoding::JsonParsed => {
|
||||
if let Ok(parsed_data) =
|
||||
parse_account_data(pubkey, account.owner(), account.data(), additional_data)
|
||||
parse_account_data(pubkey, &account.owner(), &account.data(), additional_data)
|
||||
{
|
||||
UiAccountData::Json(parsed_data)
|
||||
} else {
|
||||
|
@@ -9,14 +9,14 @@ use crate::{
|
||||
};
|
||||
use inflector::Inflector;
|
||||
use serde_json::Value;
|
||||
use solana_sdk::{instruction::InstructionError, pubkey::Pubkey, stake, system_program, sysvar};
|
||||
use solana_sdk::{instruction::InstructionError, pubkey::Pubkey, system_program, sysvar};
|
||||
use std::collections::HashMap;
|
||||
use thiserror::Error;
|
||||
|
||||
lazy_static! {
|
||||
static ref BPF_UPGRADEABLE_LOADER_PROGRAM_ID: Pubkey = solana_sdk::bpf_loader_upgradeable::id();
|
||||
static ref CONFIG_PROGRAM_ID: Pubkey = solana_config_program::id();
|
||||
static ref STAKE_PROGRAM_ID: Pubkey = stake::program::id();
|
||||
static ref STAKE_PROGRAM_ID: Pubkey = solana_stake_program::id();
|
||||
static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id();
|
||||
static ref SYSVAR_PROGRAM_ID: Pubkey = sysvar::id();
|
||||
static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v2_0();
|
||||
|
@@ -6,10 +6,10 @@ use bincode::deserialize;
|
||||
use serde_json::Value;
|
||||
use solana_config_program::{get_config_data, ConfigKeys};
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_sdk::stake::config::{self as stake_config, Config as StakeConfig};
|
||||
use solana_stake_program::config::Config as StakeConfig;
|
||||
|
||||
pub fn parse_config(data: &[u8], pubkey: &Pubkey) -> Result<ConfigAccountType, ParseAccountError> {
|
||||
let parsed_account = if pubkey == &stake_config::id() {
|
||||
let parsed_account = if pubkey == &solana_stake_program::config::id() {
|
||||
get_config_data(data)
|
||||
.ok()
|
||||
.and_then(|data| deserialize::<StakeConfig>(data).ok())
|
||||
@@ -37,7 +37,7 @@ fn parse_config_data<T>(data: &[u8], keys: Vec<(Pubkey, bool)>) -> Option<UiConf
|
||||
where
|
||||
T: serde::de::DeserializeOwned,
|
||||
{
|
||||
let config_data: T = deserialize(get_config_data(data).ok()?).ok()?;
|
||||
let config_data: T = deserialize(&get_config_data(data).ok()?).ok()?;
|
||||
let keys = keys
|
||||
.iter()
|
||||
.map(|key| UiConfigKey {
|
||||
@@ -101,7 +101,11 @@ mod test {
|
||||
};
|
||||
let stake_config_account = create_config_account(vec![], &stake_config, 10);
|
||||
assert_eq!(
|
||||
parse_config(stake_config_account.data(), &stake_config::id()).unwrap(),
|
||||
parse_config(
|
||||
&stake_config_account.data(),
|
||||
&solana_stake_program::config::id()
|
||||
)
|
||||
.unwrap(),
|
||||
ConfigAccountType::StakeConfig(UiStakeConfig {
|
||||
warmup_cooldown_rate: 0.25,
|
||||
slash_penalty: 50,
|
||||
@@ -121,7 +125,7 @@ mod test {
|
||||
10,
|
||||
);
|
||||
assert_eq!(
|
||||
parse_config(validator_info_config_account.data(), &info_pubkey).unwrap(),
|
||||
parse_config(&validator_info_config_account.data(), &info_pubkey).unwrap(),
|
||||
ConfigAccountType::ValidatorInfo(UiConfig {
|
||||
keys: vec![
|
||||
UiConfigKey {
|
||||
|
@@ -4,7 +4,7 @@ use crate::{
|
||||
};
|
||||
use bincode::deserialize;
|
||||
use solana_sdk::clock::{Epoch, UnixTimestamp};
|
||||
use solana_sdk::stake::state::{Authorized, Delegation, Lockup, Meta, Stake, StakeState};
|
||||
use solana_stake_program::stake_state::{Authorized, Delegation, Lockup, Meta, Stake, StakeState};
|
||||
|
||||
pub fn parse_stake(data: &[u8]) -> Result<StakeAccountType, ParseAccountError> {
|
||||
let stake_state: StakeState = deserialize(data)
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-accounts-bench"
|
||||
version = "1.7.14"
|
||||
version = "1.6.28"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -11,11 +11,11 @@ publish = false
|
||||
[dependencies]
|
||||
log = "0.4.11"
|
||||
rayon = "1.5.0"
|
||||
solana-logger = { path = "../logger", version = "=1.7.14" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.7.14" }
|
||||
solana-measure = { path = "../measure", version = "=1.7.14" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.14" }
|
||||
solana-version = { path = "../version", version = "=1.7.14" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.28" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.28" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.28" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.28" }
|
||||
solana-version = { path = "../version", version = "=1.6.28" }
|
||||
rand = "0.7.0"
|
||||
clap = "2.33.1"
|
||||
crossbeam-channel = "0.4"
|
||||
|
@@ -6,9 +6,7 @@ use rayon::prelude::*;
|
||||
use solana_measure::measure::Measure;
|
||||
use solana_runtime::{
|
||||
accounts::{create_test_accounts, update_accounts_bench, Accounts},
|
||||
accounts_db::AccountShrinkThreshold,
|
||||
accounts_index::AccountSecondaryIndexes,
|
||||
ancestors::Ancestors,
|
||||
accounts_index::{AccountSecondaryIndexes, Ancestors},
|
||||
};
|
||||
use solana_sdk::{genesis_config::ClusterType, pubkey::Pubkey};
|
||||
use std::{env, fs, path::PathBuf};
|
||||
@@ -65,7 +63,6 @@ fn main() {
|
||||
&ClusterType::Testnet,
|
||||
AccountSecondaryIndexes::default(),
|
||||
false,
|
||||
AccountShrinkThreshold::default(),
|
||||
);
|
||||
println!("Creating {} accounts", num_accounts);
|
||||
let mut create_time = Measure::start("create accounts");
|
||||
@@ -90,19 +87,17 @@ fn main() {
|
||||
num_slots,
|
||||
create_time
|
||||
);
|
||||
let mut ancestors = Vec::with_capacity(num_slots);
|
||||
ancestors.push(0);
|
||||
let mut ancestors: Ancestors = vec![(0, 0)].into_iter().collect();
|
||||
for i in 1..num_slots {
|
||||
ancestors.push(i as u64);
|
||||
ancestors.insert(i as u64, i - 1);
|
||||
accounts.add_root(i as u64);
|
||||
}
|
||||
let ancestors = Ancestors::from(ancestors);
|
||||
let mut elapsed = vec![0; iterations];
|
||||
let mut elapsed_store = vec![0; iterations];
|
||||
for x in 0..iterations {
|
||||
if clean {
|
||||
let mut time = Measure::start("clean");
|
||||
accounts.accounts_db.clean_accounts(None, false);
|
||||
accounts.accounts_db.clean_accounts(None);
|
||||
time.stop();
|
||||
println!("{}", time);
|
||||
for slot in 0..num_slots {
|
||||
@@ -121,8 +116,6 @@ fn main() {
|
||||
solana_sdk::clock::Slot::default(),
|
||||
&ancestors,
|
||||
None,
|
||||
false,
|
||||
None,
|
||||
);
|
||||
time_store.stop();
|
||||
if results != results_store {
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-accounts-cluster-bench"
|
||||
version = "1.7.14"
|
||||
version = "1.6.28"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -13,24 +13,22 @@ clap = "2.33.1"
|
||||
log = "0.4.11"
|
||||
rand = "0.7.0"
|
||||
rayon = "1.4.1"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.7.14" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.7.14" }
|
||||
solana-client = { path = "../client", version = "=1.7.14" }
|
||||
solana-core = { path = "../core", version = "=1.7.14" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.7.14" }
|
||||
solana-gossip = { path = "../gossip", version = "=1.7.14" }
|
||||
solana-logger = { path = "../logger", version = "=1.7.14" }
|
||||
solana-measure = { path = "../measure", version = "=1.7.14" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.7.14" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.7.14" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.14" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.7.14" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.7.14" }
|
||||
solana-version = { path = "../version", version = "=1.7.14" }
|
||||
spl-token-v2-0 = { package = "spl-token", version = "=3.2.0", features = ["no-entrypoint"] }
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.28" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.28" }
|
||||
solana-client = { path = "../client", version = "=1.6.28" }
|
||||
solana-core = { path = "../core", version = "=1.6.28" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.28" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.28" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.28" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.28" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.28" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.28" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.28" }
|
||||
solana-version = { path = "../version", version = "=1.6.28" }
|
||||
spl-token-v2-0 = { package = "spl-token", version = "=3.1.1", features = ["no-entrypoint"] }
|
||||
|
||||
[dev-dependencies]
|
||||
solana-local-cluster = { path = "../local-cluster", version = "=1.7.14" }
|
||||
solana-local-cluster = { path = "../local-cluster", version = "=1.6.28" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -6,8 +6,8 @@ use rayon::prelude::*;
|
||||
use solana_account_decoder::parse_token::spl_token_v2_0_pubkey;
|
||||
use solana_clap_utils::input_parsers::pubkey_of;
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_core::gossip_service::discover;
|
||||
use solana_faucet::faucet::{request_airdrop_transaction, FAUCET_PORT};
|
||||
use solana_gossip::gossip_service::discover;
|
||||
use solana_measure::measure::Measure;
|
||||
use solana_runtime::inline_spl_token_v2_0;
|
||||
use solana_sdk::{
|
||||
@@ -20,7 +20,6 @@ use solana_sdk::{
|
||||
timing::timestamp,
|
||||
transaction::Transaction,
|
||||
};
|
||||
use solana_streamer::socket::SocketAddrSpace;
|
||||
use solana_transaction_status::parse_token::spl_token_v2_0_instruction;
|
||||
use std::{
|
||||
net::SocketAddr,
|
||||
@@ -56,7 +55,7 @@ pub fn airdrop_lamports(
|
||||
);
|
||||
|
||||
let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap();
|
||||
match request_airdrop_transaction(faucet_addr, &id.pubkey(), airdrop_amount, blockhash) {
|
||||
match request_airdrop_transaction(&faucet_addr, &id.pubkey(), airdrop_amount, blockhash) {
|
||||
Ok(transaction) => {
|
||||
let mut tries = 0;
|
||||
loop {
|
||||
@@ -364,7 +363,7 @@ fn run_accounts_bench(
|
||||
iterations: usize,
|
||||
maybe_space: Option<u64>,
|
||||
batch_size: usize,
|
||||
close_nth_batch: u64,
|
||||
close_nth: u64,
|
||||
maybe_lamports: Option<u64>,
|
||||
num_instructions: usize,
|
||||
mint: Option<Pubkey>,
|
||||
@@ -432,7 +431,7 @@ fn run_accounts_bench(
|
||||
if !airdrop_lamports(
|
||||
&client,
|
||||
&faucet_addr,
|
||||
payer_keypairs[i],
|
||||
&payer_keypairs[i],
|
||||
lamports * 100_000,
|
||||
) {
|
||||
warn!("failed airdrop, exiting");
|
||||
@@ -442,7 +441,6 @@ fn run_accounts_bench(
|
||||
}
|
||||
}
|
||||
|
||||
// Create accounts
|
||||
let sigs_len = executor.num_outstanding();
|
||||
if sigs_len < batch_size {
|
||||
let num_to_create = batch_size - sigs_len;
|
||||
@@ -477,25 +475,21 @@ fn run_accounts_bench(
|
||||
}
|
||||
}
|
||||
|
||||
if close_nth_batch > 0 {
|
||||
let num_batches_to_close =
|
||||
total_accounts_created as u64 / (close_nth_batch * batch_size as u64);
|
||||
let expected_closed = num_batches_to_close * batch_size as u64;
|
||||
let max_closed_seed = seed_tracker.max_closed.load(Ordering::Relaxed);
|
||||
// Close every account we've created with seed between max_closed_seed..expected_closed
|
||||
if max_closed_seed < expected_closed {
|
||||
let txs: Vec<_> = (0..expected_closed - max_closed_seed)
|
||||
if close_nth > 0 {
|
||||
let expected_closed = total_accounts_created as u64 / close_nth;
|
||||
if expected_closed > total_accounts_closed {
|
||||
let txs: Vec<_> = (0..expected_closed - total_accounts_closed)
|
||||
.into_par_iter()
|
||||
.map(|_| {
|
||||
let message = make_close_message(
|
||||
payer_keypairs[0],
|
||||
&payer_keypairs[0],
|
||||
&base_keypair,
|
||||
seed_tracker.max_closed.clone(),
|
||||
1,
|
||||
min_balance,
|
||||
mint.is_some(),
|
||||
);
|
||||
let signers: Vec<&Keypair> = vec![payer_keypairs[0], &base_keypair];
|
||||
let signers: Vec<&Keypair> = vec![&payer_keypairs[0], &base_keypair];
|
||||
Transaction::new(&signers, message, recent_blockhash.0)
|
||||
})
|
||||
.collect();
|
||||
@@ -578,14 +572,14 @@ fn main() {
|
||||
.help("Number of transactions to send per batch"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("close_nth_batch")
|
||||
Arg::with_name("close_nth")
|
||||
.long("close-frequency")
|
||||
.takes_value(true)
|
||||
.value_name("BYTES")
|
||||
.help(
|
||||
"Every `n` batches, create a batch of close transactions for
|
||||
the earliest remaining batch of accounts created.
|
||||
Note: Should be > 1 to avoid situations where the close \
|
||||
"Send close transactions after this many accounts created. \
|
||||
Note: a `close-frequency` value near or below `batch-size` \
|
||||
may result in transaction-simulation errors, as the close \
|
||||
transactions will be submitted before the corresponding \
|
||||
create transactions have been confirmed",
|
||||
),
|
||||
@@ -638,7 +632,7 @@ fn main() {
|
||||
let space = value_t!(matches, "space", u64).ok();
|
||||
let lamports = value_t!(matches, "lamports", u64).ok();
|
||||
let batch_size = value_t!(matches, "batch_size", usize).unwrap_or(4);
|
||||
let close_nth_batch = value_t!(matches, "close_nth_batch", u64).unwrap_or(0);
|
||||
let close_nth = value_t!(matches, "close_nth", u64).unwrap_or(0);
|
||||
let iterations = value_t!(matches, "iterations", usize).unwrap_or(10);
|
||||
let num_instructions = value_t!(matches, "num_instructions", usize).unwrap_or(1);
|
||||
if num_instructions == 0 || num_instructions > 500 {
|
||||
@@ -671,7 +665,6 @@ fn main() {
|
||||
Some(&entrypoint_addr), // find_node_by_gossip_addr
|
||||
None, // my_gossip_addr
|
||||
0, // my_shred_version
|
||||
SocketAddrSpace::Unspecified,
|
||||
)
|
||||
.unwrap_or_else(|err| {
|
||||
eprintln!("Failed to discover {} node: {:?}", entrypoint_addr, err);
|
||||
@@ -692,7 +685,7 @@ fn main() {
|
||||
iterations,
|
||||
space,
|
||||
batch_size,
|
||||
close_nth_batch,
|
||||
close_nth,
|
||||
lamports,
|
||||
num_instructions,
|
||||
mint,
|
||||
@@ -723,11 +716,11 @@ pub mod test {
|
||||
};
|
||||
|
||||
let faucet_addr = SocketAddr::from(([127, 0, 0, 1], 9900));
|
||||
let cluster = LocalCluster::new(&mut config, SocketAddrSpace::Unspecified);
|
||||
let cluster = LocalCluster::new(&mut config);
|
||||
let iterations = 10;
|
||||
let maybe_space = None;
|
||||
let batch_size = 100;
|
||||
let close_nth_batch = 100;
|
||||
let close_nth = 100;
|
||||
let maybe_lamports = None;
|
||||
let num_instructions = 2;
|
||||
let mut start = Measure::start("total accounts run");
|
||||
@@ -738,7 +731,7 @@ pub mod test {
|
||||
iterations,
|
||||
maybe_space,
|
||||
batch_size,
|
||||
close_nth_batch,
|
||||
close_nth,
|
||||
maybe_lamports,
|
||||
num_instructions,
|
||||
None,
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-banking-bench"
|
||||
version = "1.7.14"
|
||||
version = "1.6.28"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -14,18 +14,16 @@ crossbeam-channel = "0.4"
|
||||
log = "0.4.11"
|
||||
rand = "0.7.0"
|
||||
rayon = "1.5.0"
|
||||
solana-core = { path = "../core", version = "=1.7.14" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.7.14" }
|
||||
solana-gossip = { path = "../gossip", version = "=1.7.14" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.7.14" }
|
||||
solana-logger = { path = "../logger", version = "=1.7.14" }
|
||||
solana-measure = { path = "../measure", version = "=1.7.14" }
|
||||
solana-perf = { path = "../perf", version = "=1.7.14" }
|
||||
solana-poh = { path = "../poh", version = "=1.7.14" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.7.14" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.7.14" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.14" }
|
||||
solana-version = { path = "../version", version = "=1.7.14" }
|
||||
solana-core = { path = "../core", version = "=1.6.28" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.28" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.6.28" }
|
||||
solana-perf = { path = "../perf", version = "=1.6.28" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.6.28" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.28" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.28" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.28" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.28" }
|
||||
solana-version = { path = "../version", version = "=1.6.28" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -4,8 +4,13 @@ use crossbeam_channel::unbounded;
|
||||
use log::*;
|
||||
use rand::{thread_rng, Rng};
|
||||
use rayon::prelude::*;
|
||||
use solana_core::banking_stage::BankingStage;
|
||||
use solana_gossip::{cluster_info::ClusterInfo, cluster_info::Node};
|
||||
use solana_core::{
|
||||
banking_stage::{create_test_recorder, BankingStage},
|
||||
cluster_info::ClusterInfo,
|
||||
cluster_info::Node,
|
||||
poh_recorder::PohRecorder,
|
||||
poh_recorder::WorkingBankEntry,
|
||||
};
|
||||
use solana_ledger::{
|
||||
blockstore::Blockstore,
|
||||
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
||||
@@ -13,7 +18,6 @@ use solana_ledger::{
|
||||
};
|
||||
use solana_measure::measure::Measure;
|
||||
use solana_perf::packet::to_packets_chunked;
|
||||
use solana_poh::poh_recorder::{create_test_recorder, PohRecorder, WorkingBankEntry};
|
||||
use solana_runtime::{
|
||||
accounts_background_service::AbsRequestSender, bank::Bank, bank_forks::BankForks,
|
||||
};
|
||||
@@ -25,7 +29,6 @@ use solana_sdk::{
|
||||
timing::{duration_as_us, timestamp},
|
||||
transaction::Transaction,
|
||||
};
|
||||
use solana_streamer::socket::SocketAddrSpace;
|
||||
use std::{
|
||||
sync::{atomic::Ordering, mpsc::Receiver, Arc, Mutex},
|
||||
thread::sleep,
|
||||
@@ -75,7 +78,7 @@ fn make_accounts_txs(
|
||||
.into_par_iter()
|
||||
.map(|_| {
|
||||
let mut new = dummy.clone();
|
||||
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen::<u8>()).collect();
|
||||
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
|
||||
if !same_payer {
|
||||
new.message.account_keys[0] = solana_sdk::pubkey::new_rand();
|
||||
}
|
||||
@@ -166,7 +169,6 @@ fn main() {
|
||||
|
||||
let (verified_sender, verified_receiver) = unbounded();
|
||||
let (vote_sender, vote_receiver) = unbounded();
|
||||
let (tpu_vote_sender, tpu_vote_receiver) = unbounded();
|
||||
let (replay_vote_sender, _replay_vote_receiver) = unbounded();
|
||||
let bank0 = Bank::new(&genesis_config);
|
||||
let mut bank_forks = BankForks::new(bank0);
|
||||
@@ -187,7 +189,7 @@ fn main() {
|
||||
genesis_config.hash(),
|
||||
);
|
||||
// Ignore any pesky duplicate signature errors in the case we are using single-payer
|
||||
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen::<u8>()).collect();
|
||||
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
|
||||
fund.signatures = vec![Signature::new(&sig[0..64])];
|
||||
let x = bank.process_transaction(&fund);
|
||||
x.unwrap();
|
||||
@@ -197,7 +199,7 @@ fn main() {
|
||||
if !skip_sanity {
|
||||
//sanity check, make sure all the transactions can execute sequentially
|
||||
transactions.iter().for_each(|tx| {
|
||||
let res = bank.process_transaction(tx);
|
||||
let res = bank.process_transaction(&tx);
|
||||
assert!(res.is_ok(), "sanity test transactions error: {:?}", res);
|
||||
});
|
||||
bank.clear_signatures();
|
||||
@@ -217,17 +219,12 @@ fn main() {
|
||||
);
|
||||
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()),
|
||||
SocketAddrSpace::Unspecified,
|
||||
);
|
||||
let cluster_info = ClusterInfo::new_with_invalid_keypair(Node::new_localhost().info);
|
||||
let cluster_info = Arc::new(cluster_info);
|
||||
let banking_stage = BankingStage::new(
|
||||
&cluster_info,
|
||||
&poh_recorder,
|
||||
verified_receiver,
|
||||
tpu_vote_receiver,
|
||||
vote_receiver,
|
||||
None,
|
||||
replay_vote_sender,
|
||||
@@ -358,7 +355,7 @@ fn main() {
|
||||
if bank.slot() > 0 && bank.slot() % 16 == 0 {
|
||||
for tx in transactions.iter_mut() {
|
||||
tx.message.recent_blockhash = bank.last_blockhash();
|
||||
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen::<u8>()).collect();
|
||||
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
|
||||
tx.signatures[0] = Signature::new(&sig[0..64]);
|
||||
}
|
||||
verified = to_packets_chunked(&transactions.clone(), packets_per_chunk);
|
||||
@@ -383,7 +380,6 @@ fn main() {
|
||||
);
|
||||
|
||||
drop(verified_sender);
|
||||
drop(tpu_vote_sender);
|
||||
drop(vote_sender);
|
||||
exit.store(true, Ordering::Relaxed);
|
||||
banking_stage.join().unwrap();
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-banks-client"
|
||||
version = "1.7.14"
|
||||
version = "1.6.28"
|
||||
description = "Solana banks client"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -15,16 +15,16 @@ borsh = "0.9.0"
|
||||
borsh-derive = "0.9.0"
|
||||
futures = "0.3"
|
||||
mio = "0.7.6"
|
||||
solana-banks-interface = { path = "../banks-interface", version = "=1.7.14" }
|
||||
solana-program = { path = "../sdk/program", version = "=1.7.14" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.14" }
|
||||
solana-banks-interface = { path = "../banks-interface", version = "=1.6.28" }
|
||||
solana-program = { path = "../sdk/program", version = "=1.6.28" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.28" }
|
||||
tarpc = { version = "0.24.1", features = ["full"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tokio-serde = { version = "0.8", features = ["bincode"] }
|
||||
|
||||
[dev-dependencies]
|
||||
solana-runtime = { path = "../runtime", version = "=1.7.14" }
|
||||
solana-banks-server = { path = "../banks-server", version = "=1.7.14" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.28" }
|
||||
solana-banks-server = { path = "../banks-server", version = "=1.6.28" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib"]
|
||||
|
@@ -10,14 +10,8 @@ use futures::{future::join_all, Future, FutureExt};
|
||||
pub use solana_banks_interface::{BanksClient as TarpcClient, TransactionStatus};
|
||||
use solana_banks_interface::{BanksRequest, BanksResponse};
|
||||
use solana_program::{
|
||||
clock::Clock,
|
||||
clock::Slot,
|
||||
fee_calculator::FeeCalculator,
|
||||
hash::Hash,
|
||||
program_pack::Pack,
|
||||
pubkey::Pubkey,
|
||||
rent::Rent,
|
||||
sysvar::{self, Sysvar},
|
||||
clock::Slot, fee_calculator::FeeCalculator, hash::Hash, program_pack::Pack, pubkey::Pubkey,
|
||||
rent::Rent, sysvar,
|
||||
};
|
||||
use solana_sdk::{
|
||||
account::{from_account, Account},
|
||||
@@ -69,7 +63,7 @@ impl BanksClient {
|
||||
&mut self,
|
||||
ctx: Context,
|
||||
commitment: CommitmentLevel,
|
||||
) -> impl Future<Output = io::Result<(FeeCalculator, Hash, u64)>> + '_ {
|
||||
) -> impl Future<Output = io::Result<(FeeCalculator, Hash, Slot)>> + '_ {
|
||||
self.inner
|
||||
.get_fees_with_commitment_and_context(ctx, commitment)
|
||||
}
|
||||
@@ -91,14 +85,6 @@ impl BanksClient {
|
||||
self.inner.get_slot_with_context(ctx, commitment)
|
||||
}
|
||||
|
||||
pub fn get_block_height_with_context(
|
||||
&mut self,
|
||||
ctx: Context,
|
||||
commitment: CommitmentLevel,
|
||||
) -> impl Future<Output = io::Result<Slot>> + '_ {
|
||||
self.inner.get_block_height_with_context(ctx, commitment)
|
||||
}
|
||||
|
||||
pub fn process_transaction_with_commitment_and_context(
|
||||
&mut self,
|
||||
ctx: Context,
|
||||
@@ -129,39 +115,24 @@ impl BanksClient {
|
||||
self.send_transaction_with_context(context::current(), transaction)
|
||||
}
|
||||
|
||||
/// Return the cluster clock
|
||||
pub fn get_clock(&mut self) -> impl Future<Output = io::Result<Clock>> + '_ {
|
||||
self.get_account(sysvar::clock::id()).map(|result| {
|
||||
let clock_sysvar = result?
|
||||
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Clock sysvar not present"))?;
|
||||
from_account::<Clock, _>(&clock_sysvar).ok_or_else(|| {
|
||||
io::Error::new(io::ErrorKind::Other, "Failed to deserialize Clock sysvar")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the fee parameters associated with a recent, rooted blockhash. The cluster
|
||||
/// will use the transaction's blockhash to look up these same fee parameters and
|
||||
/// use them to calculate the transaction fee.
|
||||
pub fn get_fees(
|
||||
&mut self,
|
||||
) -> impl Future<Output = io::Result<(FeeCalculator, Hash, u64)>> + '_ {
|
||||
) -> impl Future<Output = io::Result<(FeeCalculator, Hash, Slot)>> + '_ {
|
||||
self.get_fees_with_commitment_and_context(context::current(), CommitmentLevel::default())
|
||||
}
|
||||
|
||||
/// Return the cluster Sysvar
|
||||
pub fn get_sysvar<T: Sysvar>(&mut self) -> impl Future<Output = io::Result<T>> + '_ {
|
||||
self.get_account(T::id()).map(|result| {
|
||||
let sysvar = result?
|
||||
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Sysvar not present"))?;
|
||||
from_account::<T, _>(&sysvar)
|
||||
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Failed to deserialize sysvar"))
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the cluster rent
|
||||
pub fn get_rent(&mut self) -> impl Future<Output = io::Result<Rent>> + '_ {
|
||||
self.get_sysvar::<Rent>()
|
||||
self.get_account(sysvar::rent::id()).map(|result| {
|
||||
let rent_sysvar = result?
|
||||
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Rent sysvar not present"))?;
|
||||
from_account::<Rent, _>(&rent_sysvar).ok_or_else(|| {
|
||||
io::Error::new(io::ErrorKind::Other, "Failed to deserialize Rent sysvar")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Return a recent, rooted blockhash from the server. The cluster will only accept
|
||||
@@ -221,18 +192,12 @@ impl BanksClient {
|
||||
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.
|
||||
/// Return the most recent rooted slot height. All transactions at or below this height
|
||||
/// are said to be finalized. The cluster will not fork to a higher slot height.
|
||||
pub fn get_root_slot(&mut self) -> impl Future<Output = io::Result<Slot>> + '_ {
|
||||
self.get_slot_with_context(context::current(), CommitmentLevel::default())
|
||||
}
|
||||
|
||||
/// Return the most recent rooted block height. All transactions at or below this height
|
||||
/// are said to be finalized. The cluster will not fork to a higher block height.
|
||||
pub fn get_root_block_height(&mut self) -> impl Future<Output = io::Result<Slot>> + '_ {
|
||||
self.get_block_height_with_context(context::current(), CommitmentLevel::default())
|
||||
}
|
||||
|
||||
/// Return the account at the given address at the slot corresponding to the given
|
||||
/// commitment level. If the account is not found, None is returned.
|
||||
pub fn get_account_with_commitment(
|
||||
@@ -412,13 +377,13 @@ mod tests {
|
||||
|
||||
let mint_pubkey = &genesis.mint_keypair.pubkey();
|
||||
let bob_pubkey = solana_sdk::pubkey::new_rand();
|
||||
let instruction = system_instruction::transfer(mint_pubkey, &bob_pubkey, 1);
|
||||
let message = Message::new(&[instruction], Some(mint_pubkey));
|
||||
let instruction = system_instruction::transfer(&mint_pubkey, &bob_pubkey, 1);
|
||||
let message = Message::new(&[instruction], Some(&mint_pubkey));
|
||||
|
||||
Runtime::new()?.block_on(async {
|
||||
let client_transport = start_local_server(bank_forks, block_commitment_cache).await;
|
||||
let mut banks_client = start_client(client_transport).await?;
|
||||
let (_, recent_blockhash, last_valid_block_height) = banks_client.get_fees().await?;
|
||||
let (_, recent_blockhash, last_valid_slot) = banks_client.get_fees().await?;
|
||||
let transaction = Transaction::new(&[&genesis.mint_keypair], message, recent_blockhash);
|
||||
let signature = transaction.signatures[0];
|
||||
banks_client.send_transaction(transaction).await?;
|
||||
@@ -426,8 +391,8 @@ mod tests {
|
||||
let mut status = banks_client.get_transaction_status(signature).await?;
|
||||
|
||||
while status.is_none() {
|
||||
let root_block_height = banks_client.get_root_block_height().await?;
|
||||
if root_block_height > last_valid_block_height {
|
||||
let root_slot = banks_client.get_root_slot().await?;
|
||||
if root_slot > last_valid_slot {
|
||||
break;
|
||||
}
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-banks-interface"
|
||||
version = "1.7.14"
|
||||
version = "1.6.28"
|
||||
description = "Solana banks RPC interface"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -12,7 +12,7 @@ edition = "2018"
|
||||
[dependencies]
|
||||
mio = "0.7.6"
|
||||
serde = { version = "1.0.122", features = ["derive"] }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.14" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.28" }
|
||||
tarpc = { version = "0.24.1", features = ["full"] }
|
||||
|
||||
[dev-dependencies]
|
||||
|
@@ -34,7 +34,6 @@ pub trait Banks {
|
||||
async fn get_transaction_status_with_context(signature: Signature)
|
||||
-> Option<TransactionStatus>;
|
||||
async fn get_slot_with_context(commitment: CommitmentLevel) -> Slot;
|
||||
async fn get_block_height_with_context(commitment: CommitmentLevel) -> u64;
|
||||
async fn process_transaction_with_commitment_and_context(
|
||||
transaction: Transaction,
|
||||
commitment: CommitmentLevel,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-banks-server"
|
||||
version = "1.7.14"
|
||||
version = "1.6.28"
|
||||
description = "Solana banks server"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -14,10 +14,10 @@ bincode = "1.3.1"
|
||||
futures = "0.3"
|
||||
log = "0.4.11"
|
||||
mio = "0.7.6"
|
||||
solana-banks-interface = { path = "../banks-interface", version = "=1.7.14" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.7.14" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.14" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.7.14" }
|
||||
solana-banks-interface = { path = "../banks-interface", version = "=1.6.28" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.28" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.28" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.28" }
|
||||
tarpc = { version = "0.24.1", features = ["full"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tokio-serde = { version = "0.8", features = ["bincode"] }
|
||||
|
@@ -113,7 +113,7 @@ impl BanksServer {
|
||||
self,
|
||||
signature: &Signature,
|
||||
blockhash: &Hash,
|
||||
last_valid_block_height: u64,
|
||||
last_valid_slot: Slot,
|
||||
commitment: CommitmentLevel,
|
||||
) -> Option<transaction::Result<()>> {
|
||||
let mut status = self
|
||||
@@ -122,7 +122,7 @@ impl BanksServer {
|
||||
while status.is_none() {
|
||||
sleep(Duration::from_millis(200)).await;
|
||||
let bank = self.bank(commitment);
|
||||
if bank.block_height() > last_valid_block_height {
|
||||
if bank.slot() > last_valid_slot {
|
||||
break;
|
||||
}
|
||||
status = bank.get_signature_status_with_blockhash(signature, blockhash);
|
||||
@@ -148,19 +148,16 @@ fn verify_transaction(
|
||||
impl Banks for BanksServer {
|
||||
async fn send_transaction_with_context(self, _: Context, transaction: Transaction) {
|
||||
let blockhash = &transaction.message.recent_blockhash;
|
||||
let last_valid_block_height = self
|
||||
let last_valid_slot = self
|
||||
.bank_forks
|
||||
.read()
|
||||
.unwrap()
|
||||
.root_bank()
|
||||
.get_blockhash_last_valid_block_height(blockhash)
|
||||
.get_blockhash_last_valid_slot(&blockhash)
|
||||
.unwrap();
|
||||
let signature = transaction.signatures.get(0).cloned().unwrap_or_default();
|
||||
let info = TransactionInfo::new(
|
||||
signature,
|
||||
serialize(&transaction).unwrap(),
|
||||
last_valid_block_height,
|
||||
);
|
||||
let info =
|
||||
TransactionInfo::new(signature, serialize(&transaction).unwrap(), last_valid_slot);
|
||||
self.transaction_sender.send(info).unwrap();
|
||||
}
|
||||
|
||||
@@ -168,13 +165,11 @@ impl Banks for BanksServer {
|
||||
self,
|
||||
_: Context,
|
||||
commitment: CommitmentLevel,
|
||||
) -> (FeeCalculator, Hash, u64) {
|
||||
) -> (FeeCalculator, Hash, Slot) {
|
||||
let bank = self.bank(commitment);
|
||||
let (blockhash, fee_calculator) = bank.last_blockhash_with_fee_calculator();
|
||||
let last_valid_block_height = bank
|
||||
.get_blockhash_last_valid_block_height(&blockhash)
|
||||
.unwrap();
|
||||
(fee_calculator, blockhash, last_valid_block_height)
|
||||
let last_valid_slot = bank.get_blockhash_last_valid_slot(&blockhash).unwrap();
|
||||
(fee_calculator, blockhash, last_valid_slot)
|
||||
}
|
||||
|
||||
async fn get_transaction_status_with_context(
|
||||
@@ -217,10 +212,6 @@ impl Banks for BanksServer {
|
||||
self.slot(commitment)
|
||||
}
|
||||
|
||||
async fn get_block_height_with_context(self, _: Context, commitment: CommitmentLevel) -> u64 {
|
||||
self.bank(commitment).block_height()
|
||||
}
|
||||
|
||||
async fn process_transaction_with_commitment_and_context(
|
||||
self,
|
||||
_: Context,
|
||||
@@ -235,21 +226,18 @@ impl Banks for BanksServer {
|
||||
}
|
||||
|
||||
let blockhash = &transaction.message.recent_blockhash;
|
||||
let last_valid_block_height = self
|
||||
let last_valid_slot = self
|
||||
.bank_forks
|
||||
.read()
|
||||
.unwrap()
|
||||
.root_bank()
|
||||
.get_blockhash_last_valid_block_height(blockhash)
|
||||
.get_blockhash_last_valid_slot(blockhash)
|
||||
.unwrap();
|
||||
let signature = transaction.signatures.get(0).cloned().unwrap_or_default();
|
||||
let info = TransactionInfo::new(
|
||||
signature,
|
||||
serialize(&transaction).unwrap(),
|
||||
last_valid_block_height,
|
||||
);
|
||||
let info =
|
||||
TransactionInfo::new(signature, serialize(&transaction).unwrap(), last_valid_slot);
|
||||
self.transaction_sender.send(info).unwrap();
|
||||
self.poll_signature_status(&signature, blockhash, last_valid_block_height, commitment)
|
||||
self.poll_signature_status(&signature, blockhash, last_valid_slot, commitment)
|
||||
.await
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
use log::*;
|
||||
use solana_metrics::{datapoint_warn, inc_new_counter_info};
|
||||
use solana_runtime::{bank::Bank, bank_forks::BankForks};
|
||||
use solana_sdk::signature::Signature;
|
||||
use solana_sdk::{clock::Slot, signature::Signature};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
net::{SocketAddr, UdpSocket},
|
||||
@@ -24,19 +24,15 @@ pub struct SendTransactionService {
|
||||
pub struct TransactionInfo {
|
||||
pub signature: Signature,
|
||||
pub wire_transaction: Vec<u8>,
|
||||
pub last_valid_block_height: u64,
|
||||
pub last_valid_slot: Slot,
|
||||
}
|
||||
|
||||
impl TransactionInfo {
|
||||
pub fn new(
|
||||
signature: Signature,
|
||||
wire_transaction: Vec<u8>,
|
||||
last_valid_block_height: u64,
|
||||
) -> Self {
|
||||
pub fn new(signature: Signature, wire_transaction: Vec<u8>, last_valid_slot: Slot) -> Self {
|
||||
Self {
|
||||
signature,
|
||||
wire_transaction,
|
||||
last_valid_block_height,
|
||||
last_valid_slot,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,7 +124,7 @@ impl SendTransactionService {
|
||||
result.rooted += 1;
|
||||
inc_new_counter_info!("send_transaction_service-rooted", 1);
|
||||
false
|
||||
} else if transaction_info.last_valid_block_height < root_bank.block_height() {
|
||||
} else if transaction_info.last_valid_slot < root_bank.slot() {
|
||||
info!("Dropping expired transaction: {}", signature);
|
||||
result.expired += 1;
|
||||
inc_new_counter_info!("send_transaction_service-expired", 1);
|
||||
@@ -142,8 +138,8 @@ impl SendTransactionService {
|
||||
result.retried += 1;
|
||||
inc_new_counter_info!("send_transaction_service-retry", 1);
|
||||
Self::send_transaction(
|
||||
send_socket,
|
||||
tpu_address,
|
||||
&send_socket,
|
||||
&tpu_address,
|
||||
&transaction_info.wire_transaction,
|
||||
);
|
||||
true
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-bench-exchange"
|
||||
version = "1.7.14"
|
||||
version = "1.6.28"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -18,23 +18,21 @@ rand = "0.7.0"
|
||||
rayon = "1.5.0"
|
||||
serde_json = "1.0.56"
|
||||
serde_yaml = "0.8.13"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.7.14" }
|
||||
solana-core = { path = "../core", version = "=1.7.14" }
|
||||
solana-genesis = { path = "../genesis", version = "=1.7.14" }
|
||||
solana-client = { path = "../client", version = "=1.7.14" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "=1.7.14" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.7.14" }
|
||||
solana-gossip = { path = "../gossip", version = "=1.7.14" }
|
||||
solana-logger = { path = "../logger", version = "=1.7.14" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.7.14" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.7.14" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.7.14" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.14" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.7.14" }
|
||||
solana-version = { path = "../version", version = "=1.7.14" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.28" }
|
||||
solana-core = { path = "../core", version = "=1.6.28" }
|
||||
solana-genesis = { path = "../genesis", version = "=1.6.28" }
|
||||
solana-client = { path = "../client", version = "=1.6.28" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.28" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "=1.6.28" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.28" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.28" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.28" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.28" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.28" }
|
||||
solana-version = { path = "../version", version = "=1.6.28" }
|
||||
|
||||
[dev-dependencies]
|
||||
solana-local-cluster = { path = "../local-cluster", version = "=1.7.14" }
|
||||
solana-local-cluster = { path = "../local-cluster", version = "=1.6.28" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -451,13 +451,13 @@ fn swapper<T>(
|
||||
let to_swap_txs: Vec<_> = to_swap
|
||||
.par_iter()
|
||||
.map(|(signer, swap, profit)| {
|
||||
let s: &Keypair = signer;
|
||||
let s: &Keypair = &signer;
|
||||
let owner = &signer.pubkey();
|
||||
let instruction = exchange_instruction::swap_request(
|
||||
owner,
|
||||
&swap.0.pubkey,
|
||||
&swap.1.pubkey,
|
||||
profit,
|
||||
&profit,
|
||||
);
|
||||
let message = Message::new(&[instruction], Some(&s.pubkey()));
|
||||
Transaction::new(&[s], message, blockhash)
|
||||
@@ -600,7 +600,7 @@ fn trader<T>(
|
||||
src,
|
||||
),
|
||||
];
|
||||
let message = Message::new(&instructions, Some(owner_pubkey));
|
||||
let message = Message::new(&instructions, Some(&owner_pubkey));
|
||||
Transaction::new(&[owner.as_ref(), trade], message, blockhash)
|
||||
})
|
||||
.collect();
|
||||
@@ -739,7 +739,7 @@ pub fn fund_keys<T: Client>(client: &T, source: &Keypair, dests: &[Arc<Keypair>]
|
||||
let mut to_fund_txs: Vec<_> = chunk
|
||||
.par_iter()
|
||||
.map(|(k, m)| {
|
||||
let instructions = system_instruction::transfer_many(&k.pubkey(), m);
|
||||
let instructions = system_instruction::transfer_many(&k.pubkey(), &m);
|
||||
let message = Message::new(&instructions, Some(&k.pubkey()));
|
||||
(k.clone(), Transaction::new_unsigned(message))
|
||||
})
|
||||
@@ -777,7 +777,7 @@ pub fn fund_keys<T: Client>(client: &T, source: &Keypair, dests: &[Arc<Keypair>]
|
||||
let mut waits = 0;
|
||||
loop {
|
||||
sleep(Duration::from_millis(200));
|
||||
to_fund_txs.retain(|(_, tx)| !verify_funding_transfer(client, tx, amount));
|
||||
to_fund_txs.retain(|(_, tx)| !verify_funding_transfer(client, &tx, amount));
|
||||
if to_fund_txs.is_empty() {
|
||||
break;
|
||||
}
|
||||
@@ -836,7 +836,7 @@ pub fn create_token_accounts<T: Client>(
|
||||
);
|
||||
let request_ix =
|
||||
exchange_instruction::account_request(owner_pubkey, &new_keypair.pubkey());
|
||||
let message = Message::new(&[create_ix, request_ix], Some(owner_pubkey));
|
||||
let message = Message::new(&[create_ix, request_ix], Some(&owner_pubkey));
|
||||
(
|
||||
(from_keypair, new_keypair),
|
||||
Transaction::new_unsigned(message),
|
||||
@@ -872,7 +872,7 @@ pub fn create_token_accounts<T: Client>(
|
||||
let mut waits = 0;
|
||||
while !to_create_txs.is_empty() {
|
||||
sleep(Duration::from_millis(200));
|
||||
to_create_txs.retain(|(_, tx)| !verify_transaction(client, tx));
|
||||
to_create_txs.retain(|(_, tx)| !verify_transaction(client, &tx));
|
||||
if to_create_txs.is_empty() {
|
||||
break;
|
||||
}
|
||||
@@ -958,7 +958,7 @@ fn compute_and_report_stats(maxes: &Arc<RwLock<Vec<(String, SampleStats)>>>, tot
|
||||
|
||||
fn generate_keypairs(num: u64) -> Vec<Keypair> {
|
||||
let mut seed = [0_u8; 32];
|
||||
seed.copy_from_slice(Keypair::new().pubkey().as_ref());
|
||||
seed.copy_from_slice(&Keypair::new().pubkey().as_ref());
|
||||
let mut rnd = GenKeys::new(seed);
|
||||
rnd.gen_n_keypairs(num)
|
||||
}
|
||||
@@ -989,7 +989,7 @@ pub fn airdrop_lamports<T: Client>(
|
||||
let (blockhash, _fee_calculator, _last_valid_slot) = client
|
||||
.get_recent_blockhash_with_commitment(CommitmentConfig::processed())
|
||||
.expect("Failed to get blockhash");
|
||||
match request_airdrop_transaction(faucet_addr, &id.pubkey(), amount_to_drop, blockhash) {
|
||||
match request_airdrop_transaction(&faucet_addr, &id.pubkey(), amount_to_drop, blockhash) {
|
||||
Ok(transaction) => {
|
||||
let signature = client.async_send_transaction(transaction).unwrap();
|
||||
|
||||
|
@@ -5,9 +5,8 @@ pub mod order_book;
|
||||
|
||||
use crate::bench::{airdrop_lamports, create_client_accounts_file, do_bench_exchange, Config};
|
||||
use log::*;
|
||||
use solana_gossip::gossip_service::{discover_cluster, get_multi_client};
|
||||
use solana_core::gossip_service::{discover_cluster, get_multi_client};
|
||||
use solana_sdk::signature::Signer;
|
||||
use solana_streamer::socket::SocketAddrSpace;
|
||||
|
||||
fn main() {
|
||||
solana_logger::setup();
|
||||
@@ -56,12 +55,11 @@ fn main() {
|
||||
);
|
||||
} else {
|
||||
info!("Connecting to the cluster");
|
||||
let nodes = discover_cluster(&entrypoint_addr, num_nodes, SocketAddrSpace::Unspecified)
|
||||
.unwrap_or_else(|_| {
|
||||
panic!("Failed to discover nodes");
|
||||
});
|
||||
let nodes = discover_cluster(&entrypoint_addr, num_nodes).unwrap_or_else(|_| {
|
||||
panic!("Failed to discover nodes");
|
||||
});
|
||||
|
||||
let (client, num_clients) = get_multi_client(&nodes, &SocketAddrSpace::Unspecified);
|
||||
let (client, num_clients) = get_multi_client(&nodes);
|
||||
|
||||
info!("{} nodes found", num_clients);
|
||||
if num_clients < num_nodes {
|
||||
|
@@ -1,11 +1,13 @@
|
||||
use log::*;
|
||||
use solana_bench_exchange::bench::{airdrop_lamports, do_bench_exchange, Config};
|
||||
use solana_core::validator::ValidatorConfig;
|
||||
use solana_core::{
|
||||
gossip_service::{discover_cluster, get_multi_client},
|
||||
validator::ValidatorConfig,
|
||||
};
|
||||
use solana_exchange_program::{
|
||||
exchange_processor::process_instruction, id, solana_exchange_program,
|
||||
};
|
||||
use solana_faucet::faucet::run_local_faucet_with_port;
|
||||
use solana_gossip::gossip_service::{discover_cluster, get_multi_client};
|
||||
use solana_local_cluster::{
|
||||
local_cluster::{ClusterConfig, LocalCluster},
|
||||
validator_configs::make_identical_validator_configs,
|
||||
@@ -15,7 +17,6 @@ use solana_sdk::{
|
||||
genesis_config::create_genesis_config,
|
||||
signature::{Keypair, Signer},
|
||||
};
|
||||
use solana_streamer::socket::SocketAddrSpace;
|
||||
use std::{process::exit, sync::mpsc::channel, time::Duration};
|
||||
|
||||
#[test]
|
||||
@@ -44,19 +45,13 @@ fn test_exchange_local_cluster() {
|
||||
} = config;
|
||||
let accounts_in_groups = batch_size * account_groups;
|
||||
|
||||
let cluster = LocalCluster::new(
|
||||
&mut ClusterConfig {
|
||||
node_stakes: vec![100_000; NUM_NODES],
|
||||
cluster_lamports: 100_000_000_000_000,
|
||||
validator_configs: make_identical_validator_configs(
|
||||
&ValidatorConfig::default(),
|
||||
NUM_NODES,
|
||||
),
|
||||
native_instruction_processors: [solana_exchange_program!()].to_vec(),
|
||||
..ClusterConfig::default()
|
||||
},
|
||||
SocketAddrSpace::Unspecified,
|
||||
);
|
||||
let cluster = LocalCluster::new(&mut ClusterConfig {
|
||||
node_stakes: vec![100_000; NUM_NODES],
|
||||
cluster_lamports: 100_000_000_000_000,
|
||||
validator_configs: make_identical_validator_configs(&ValidatorConfig::default(), NUM_NODES),
|
||||
native_instruction_processors: [solana_exchange_program!()].to_vec(),
|
||||
..ClusterConfig::default()
|
||||
});
|
||||
|
||||
let faucet_keypair = Keypair::new();
|
||||
cluster.transfer(
|
||||
@@ -73,17 +68,13 @@ fn test_exchange_local_cluster() {
|
||||
.expect("faucet_addr");
|
||||
|
||||
info!("Connecting to the cluster");
|
||||
let nodes = discover_cluster(
|
||||
&cluster.entry_point_info.gossip,
|
||||
NUM_NODES,
|
||||
SocketAddrSpace::Unspecified,
|
||||
)
|
||||
.unwrap_or_else(|err| {
|
||||
error!("Failed to discover {} nodes: {:?}", NUM_NODES, err);
|
||||
exit(1);
|
||||
});
|
||||
let nodes =
|
||||
discover_cluster(&cluster.entry_point_info.gossip, NUM_NODES).unwrap_or_else(|err| {
|
||||
error!("Failed to discover {} nodes: {:?}", NUM_NODES, err);
|
||||
exit(1);
|
||||
});
|
||||
|
||||
let (client, num_clients) = get_multi_client(&nodes, &SocketAddrSpace::Unspecified);
|
||||
let (client, num_clients) = get_multi_client(&nodes);
|
||||
|
||||
info!("clients: {}", num_clients);
|
||||
assert!(num_clients >= NUM_NODES);
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-bench-streamer"
|
||||
version = "1.7.14"
|
||||
version = "1.6.28"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -10,11 +10,11 @@ publish = false
|
||||
|
||||
[dependencies]
|
||||
clap = "2.33.1"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.7.14" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.7.14" }
|
||||
solana-logger = { path = "../logger", version = "=1.7.14" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.7.14" }
|
||||
solana-version = { path = "../version", version = "=1.7.14" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.28" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.6.28" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.28" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.28" }
|
||||
solana-version = { path = "../version", version = "=1.6.28" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -18,7 +18,7 @@ fn producer(addr: &SocketAddr, exit: Arc<AtomicBool>) -> JoinHandle<()> {
|
||||
msgs.packets.resize(10, Packet::default());
|
||||
for w in msgs.packets.iter_mut() {
|
||||
w.meta.size = PACKET_DATA_SIZE;
|
||||
w.meta.set_addr(addr);
|
||||
w.meta.set_addr(&addr);
|
||||
}
|
||||
let msgs = Arc::new(msgs);
|
||||
spawn(move || loop {
|
||||
@@ -75,7 +75,7 @@ fn main() -> Result<()> {
|
||||
|
||||
let mut read_channels = Vec::new();
|
||||
let mut read_threads = Vec::new();
|
||||
let recycler = PacketsRecycler::default();
|
||||
let recycler = PacketsRecycler::new_without_limit("bench-streamer-recycler-shrink-stats");
|
||||
for _ in 0..num_sockets {
|
||||
let read = solana_net_utils::bind_to(ip_addr, port, false).unwrap();
|
||||
read.set_read_timeout(Some(Duration::new(1, 0))).unwrap();
|
||||
@@ -92,7 +92,6 @@ fn main() -> Result<()> {
|
||||
recycler.clone(),
|
||||
"bench-streamer-test",
|
||||
1,
|
||||
true,
|
||||
));
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-bench-tps"
|
||||
version = "1.7.14"
|
||||
version = "1.6.28"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -15,24 +15,22 @@ log = "0.4.11"
|
||||
rayon = "1.5.0"
|
||||
serde_json = "1.0.56"
|
||||
serde_yaml = "0.8.13"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.7.14" }
|
||||
solana-core = { path = "../core", version = "=1.7.14" }
|
||||
solana-genesis = { path = "../genesis", version = "=1.7.14" }
|
||||
solana-client = { path = "../client", version = "=1.7.14" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.7.14" }
|
||||
solana-gossip = { path = "../gossip", version = "=1.7.14" }
|
||||
solana-logger = { path = "../logger", version = "=1.7.14" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.7.14" }
|
||||
solana-measure = { path = "../measure", version = "=1.7.14" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.7.14" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.7.14" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.14" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.7.14" }
|
||||
solana-version = { path = "../version", version = "=1.7.14" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.28" }
|
||||
solana-core = { path = "../core", version = "=1.6.28" }
|
||||
solana-genesis = { path = "../genesis", version = "=1.6.28" }
|
||||
solana-client = { path = "../client", version = "=1.6.28" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.28" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.28" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.28" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.28" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.28" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.28" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.28" }
|
||||
solana-version = { path = "../version", version = "=1.6.28" }
|
||||
|
||||
[dev-dependencies]
|
||||
serial_test = "0.4.0"
|
||||
solana-local-cluster = { path = "../local-cluster", version = "=1.7.14" }
|
||||
solana-local-cluster = { path = "../local-cluster", version = "=1.6.28" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -544,12 +544,12 @@ impl<'a> FundingTransactions<'a> for Vec<(&'a Keypair, Transaction)> {
|
||||
|
||||
// re-sign retained to_fund_txes with updated blockhash
|
||||
self.sign(blockhash);
|
||||
self.send(client);
|
||||
self.send(&client);
|
||||
|
||||
// Sleep a few slots to allow transactions to process
|
||||
sleep(Duration::from_secs(1));
|
||||
|
||||
self.verify(client, to_lamports);
|
||||
self.verify(&client, to_lamports);
|
||||
|
||||
// retry anything that seems to have dropped through cracks
|
||||
// again since these txs are all or nothing, they're fine to
|
||||
@@ -564,7 +564,7 @@ impl<'a> FundingTransactions<'a> for Vec<(&'a Keypair, Transaction)> {
|
||||
let to_fund_txs: Vec<(&Keypair, Transaction)> = to_fund
|
||||
.par_iter()
|
||||
.map(|(k, t)| {
|
||||
let instructions = system_instruction::transfer_many(&k.pubkey(), t);
|
||||
let instructions = system_instruction::transfer_many(&k.pubkey(), &t);
|
||||
let message = Message::new(&instructions, Some(&k.pubkey()));
|
||||
(*k, Transaction::new_unsigned(message))
|
||||
})
|
||||
@@ -617,7 +617,7 @@ impl<'a> FundingTransactions<'a> for Vec<(&'a Keypair, Transaction)> {
|
||||
return None;
|
||||
}
|
||||
|
||||
let verified = if verify_funding_transfer(&client, tx, to_lamports) {
|
||||
let verified = if verify_funding_transfer(&client, &tx, to_lamports) {
|
||||
verified_txs.fetch_add(1, Ordering::Relaxed);
|
||||
Some(k.pubkey())
|
||||
} else {
|
||||
@@ -733,7 +733,7 @@ pub fn airdrop_lamports<T: Client>(
|
||||
);
|
||||
|
||||
let (blockhash, _fee_calculator) = get_recent_blockhash(client);
|
||||
match request_airdrop_transaction(faucet_addr, &id.pubkey(), airdrop_amount, blockhash) {
|
||||
match request_airdrop_transaction(&faucet_addr, &id.pubkey(), airdrop_amount, blockhash) {
|
||||
Ok(transaction) => {
|
||||
let mut tries = 0;
|
||||
loop {
|
||||
|
@@ -2,12 +2,11 @@
|
||||
use log::*;
|
||||
use solana_bench_tps::bench::{do_bench_tps, generate_and_fund_keypairs, generate_keypairs};
|
||||
use solana_bench_tps::cli;
|
||||
use solana_core::gossip_service::{discover_cluster, get_client, get_multi_client};
|
||||
use solana_genesis::Base64Account;
|
||||
use solana_gossip::gossip_service::{discover_cluster, get_client, get_multi_client};
|
||||
use solana_sdk::fee_calculator::FeeRateGovernor;
|
||||
use solana_sdk::signature::{Keypair, Signer};
|
||||
use solana_sdk::system_program;
|
||||
use solana_streamer::socket::SocketAddrSpace;
|
||||
use std::{collections::HashMap, fs::File, io::prelude::*, path::Path, process::exit, sync::Arc};
|
||||
|
||||
/// Number of signatures for all transactions in ~1 week at ~100K TPS
|
||||
@@ -40,7 +39,7 @@ fn main() {
|
||||
let keypair_count = *tx_count * keypair_multiplier;
|
||||
if *write_to_client_file {
|
||||
info!("Generating {} keypairs", keypair_count);
|
||||
let (keypairs, _) = generate_keypairs(id, keypair_count as u64);
|
||||
let (keypairs, _) = generate_keypairs(&id, keypair_count as u64);
|
||||
let num_accounts = keypairs.len() as u64;
|
||||
let max_fee =
|
||||
FeeRateGovernor::new(*target_lamports_per_signature, 0).max_lamports_per_signature;
|
||||
@@ -69,14 +68,13 @@ 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);
|
||||
});
|
||||
let nodes = discover_cluster(&entrypoint_addr, *num_nodes).unwrap_or_else(|err| {
|
||||
eprintln!("Failed to discover {} nodes: {:?}", num_nodes, err);
|
||||
exit(1);
|
||||
});
|
||||
|
||||
let client = if *multi_client {
|
||||
let (client, num_clients) = get_multi_client(&nodes, &SocketAddrSpace::Unspecified);
|
||||
let (client, num_clients) = get_multi_client(&nodes);
|
||||
if nodes.len() < num_clients {
|
||||
eprintln!(
|
||||
"Error: Insufficient nodes discovered. Expecting {} or more",
|
||||
@@ -90,7 +88,7 @@ fn main() {
|
||||
let mut target_client = None;
|
||||
for node in nodes {
|
||||
if node.id == *target_node {
|
||||
target_client = Some(Arc::new(get_client(&[node], &SocketAddrSpace::Unspecified)));
|
||||
target_client = Some(Arc::new(get_client(&[node])));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -99,7 +97,7 @@ fn main() {
|
||||
exit(1);
|
||||
})
|
||||
} else {
|
||||
Arc::new(get_client(&nodes, &SocketAddrSpace::Unspecified))
|
||||
Arc::new(get_client(&nodes))
|
||||
};
|
||||
|
||||
let keypairs = if *read_from_client_file {
|
||||
@@ -137,7 +135,7 @@ fn main() {
|
||||
generate_and_fund_keypairs(
|
||||
client.clone(),
|
||||
Some(*faucet_addr),
|
||||
id,
|
||||
&id,
|
||||
keypair_count,
|
||||
*num_lamports_per_account,
|
||||
)
|
||||
|
@@ -5,15 +5,13 @@ use solana_bench_tps::{
|
||||
cli::Config,
|
||||
};
|
||||
use solana_client::thin_client::create_client;
|
||||
use solana_core::validator::ValidatorConfig;
|
||||
use solana_core::{cluster_info::VALIDATOR_PORT_RANGE, validator::ValidatorConfig};
|
||||
use solana_faucet::faucet::run_local_faucet_with_port;
|
||||
use solana_gossip::cluster_info::VALIDATOR_PORT_RANGE;
|
||||
use solana_local_cluster::{
|
||||
local_cluster::{ClusterConfig, LocalCluster},
|
||||
validator_configs::make_identical_validator_configs,
|
||||
};
|
||||
use solana_sdk::signature::{Keypair, Signer};
|
||||
use solana_streamer::socket::SocketAddrSpace;
|
||||
use std::{
|
||||
sync::{mpsc::channel, Arc},
|
||||
time::Duration,
|
||||
@@ -24,19 +22,13 @@ fn test_bench_tps_local_cluster(config: Config) {
|
||||
|
||||
solana_logger::setup();
|
||||
const NUM_NODES: usize = 1;
|
||||
let cluster = LocalCluster::new(
|
||||
&mut ClusterConfig {
|
||||
node_stakes: vec![999_990; NUM_NODES],
|
||||
cluster_lamports: 200_000_000,
|
||||
validator_configs: make_identical_validator_configs(
|
||||
&ValidatorConfig::default(),
|
||||
NUM_NODES,
|
||||
),
|
||||
native_instruction_processors,
|
||||
..ClusterConfig::default()
|
||||
},
|
||||
SocketAddrSpace::Unspecified,
|
||||
);
|
||||
let cluster = LocalCluster::new(&mut ClusterConfig {
|
||||
node_stakes: vec![999_990; NUM_NODES],
|
||||
cluster_lamports: 200_000_000,
|
||||
validator_configs: make_identical_validator_configs(&ValidatorConfig::default(), NUM_NODES),
|
||||
native_instruction_processors,
|
||||
..ClusterConfig::default()
|
||||
});
|
||||
|
||||
let faucet_keypair = Keypair::new();
|
||||
cluster.transfer(
|
||||
|
@@ -7,6 +7,11 @@ steps:
|
||||
- "queue=release-build"
|
||||
timeout_in_minutes: 60
|
||||
name: "publish tarball"
|
||||
- command: "ci/publish-bpf-sdk.sh"
|
||||
agents:
|
||||
- "queue=release-build"
|
||||
timeout_in_minutes: 5
|
||||
name: "publish bpf sdk"
|
||||
- wait
|
||||
- command: "sdk/docker-solana/build.sh"
|
||||
agents:
|
||||
|
@@ -45,5 +45,12 @@ cargo_audit_ignores=(
|
||||
# Blocked on jsonrpc removing dependency on unmaintained `websocket`
|
||||
# https://github.com/paritytech/jsonrpc/issues/605
|
||||
--ignore RUSTSEC-2021-0079
|
||||
|
||||
# tar: Links in archive can create arbitrary directories
|
||||
#
|
||||
# Blocked on `tar` releasing safe upgrade
|
||||
# https://github.com/alexcrichton/tar-rs/issues/238
|
||||
--ignore RUSTSEC-2021-0080
|
||||
|
||||
)
|
||||
scripts/cargo-for-all-lock-files.sh stable audit "${cargo_audit_ignores[@]}"
|
||||
|
@@ -1,4 +1,4 @@
|
||||
FROM solanalabs/rust:1.52.1
|
||||
FROM solanalabs/rust:1.51.0
|
||||
ARG date
|
||||
|
||||
RUN set -x \
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# Note: when the rust version is changed also modify
|
||||
# ci/rust-version.sh to pick up the new image tag
|
||||
FROM rust:1.52.1
|
||||
FROM rust:1.51.0
|
||||
|
||||
# Add Google Protocol Buffers for Libra's metrics library.
|
||||
ENV PROTOC_VERSION 3.8.0
|
||||
|
27
ci/publish-bpf-sdk.sh
Executable file
27
ci/publish-bpf-sdk.sh
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
eval "$(ci/channel-info.sh)"
|
||||
|
||||
if [[ -n "$CI_TAG" ]]; then
|
||||
CHANNEL_OR_TAG=$CI_TAG
|
||||
else
|
||||
CHANNEL_OR_TAG=$CHANNEL
|
||||
fi
|
||||
|
||||
(
|
||||
set -x
|
||||
sdk/bpf/scripts/package.sh
|
||||
[[ -f bpf-sdk.tar.bz2 ]]
|
||||
)
|
||||
|
||||
source ci/upload-ci-artifact.sh
|
||||
echo --- AWS S3 Store
|
||||
if [[ -z $CHANNEL_OR_TAG ]]; then
|
||||
echo Skipped
|
||||
else
|
||||
upload-s3-artifact "/solana/bpf-sdk.tar.bz2" "s3://solana-sdk/$CHANNEL_OR_TAG/bpf-sdk.tar.bz2"
|
||||
fi
|
||||
|
||||
exit 0
|
@@ -7,7 +7,7 @@ source multinode-demo/common.sh
|
||||
|
||||
rm -rf config/run/init-completed config/ledger config/snapshot-ledger
|
||||
|
||||
SOLANA_RUN_SH_VALIDATOR_ARGS="--snapshot-interval-slots 200" timeout 120 ./scripts/run.sh &
|
||||
timeout 120 ./run.sh &
|
||||
pid=$!
|
||||
|
||||
attempts=20
|
||||
@@ -16,8 +16,6 @@ while [[ ! -f config/run/init-completed ]]; do
|
||||
if ((--attempts == 0)); then
|
||||
echo "Error: validator failed to boot"
|
||||
exit 1
|
||||
else
|
||||
echo "Checking init"
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -26,7 +24,6 @@ snapshot_slot=1
|
||||
# wait a bit longer than snapshot_slot
|
||||
while [[ $($solana_cli --url http://localhost:8899 slot --commitment processed) -le $((snapshot_slot + 1)) ]]; do
|
||||
sleep 1
|
||||
echo "Checking slot"
|
||||
done
|
||||
|
||||
$solana_validator --ledger config/ledger exit --force || true
|
||||
|
@@ -18,13 +18,13 @@
|
||||
if [[ -n $RUST_STABLE_VERSION ]]; then
|
||||
stable_version="$RUST_STABLE_VERSION"
|
||||
else
|
||||
stable_version=1.52.1
|
||||
stable_version=1.51.0
|
||||
fi
|
||||
|
||||
if [[ -n $RUST_NIGHTLY_VERSION ]]; then
|
||||
nightly_version="$RUST_NIGHTLY_VERSION"
|
||||
else
|
||||
nightly_version=2021-05-18
|
||||
nightly_version=2021-04-18
|
||||
fi
|
||||
|
||||
|
||||
|
@@ -76,7 +76,7 @@ RestartForceExitStatus=SIGPIPE
|
||||
TimeoutStartSec=10
|
||||
TimeoutStopSec=0
|
||||
KillMode=process
|
||||
LimitNOFILE=1000000
|
||||
LimitNOFILE=700000
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
@@ -8,5 +8,5 @@ source "$HERE"/utils.sh
|
||||
ensure_env || exit 1
|
||||
|
||||
# Allow more files to be opened by a user
|
||||
echo "* - nofile 1000000" > /etc/security/limits.d/90-solana-nofiles.conf
|
||||
echo "* - nofile 700000" > /etc/security/limits.d/90-solana-nofiles.conf
|
||||
|
||||
|
@@ -27,7 +27,7 @@ BENCH_ARTIFACT=current_bench_results.log
|
||||
_ "$cargo" build --manifest-path=keygen/Cargo.toml
|
||||
export PATH="$PWD/target/debug":$PATH
|
||||
|
||||
# Clear the C dependency files, if dependency moves these files are not regenerated
|
||||
# Clear the C dependency files, if dependeny moves these files are not regenerated
|
||||
test -d target/debug/bpf && find target/debug/bpf -name '*.d' -delete
|
||||
test -d target/release/bpf && find target/release/bpf -name '*.d' -delete
|
||||
|
||||
@@ -45,14 +45,6 @@ _ "$cargo" nightly bench --manifest-path sdk/Cargo.toml ${V:+--verbose} \
|
||||
_ "$cargo" nightly bench --manifest-path runtime/Cargo.toml ${V:+--verbose} \
|
||||
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
|
||||
|
||||
# Run gossip benches
|
||||
_ "$cargo" nightly bench --manifest-path gossip/Cargo.toml ${V:+--verbose} \
|
||||
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
|
||||
|
||||
# Run poh benches
|
||||
_ "$cargo" nightly bench --manifest-path poh/Cargo.toml ${V:+--verbose} \
|
||||
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
|
||||
|
||||
# Run core benches
|
||||
_ "$cargo" nightly bench --manifest-path core/Cargo.toml ${V:+--verbose} \
|
||||
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
|
||||
|
@@ -48,7 +48,7 @@ test-stable-bpf)
|
||||
"$cargo_build_bpf" --manifest-path sdk/Cargo.toml
|
||||
|
||||
# BPF Program unit tests
|
||||
"$cargo" test --manifest-path programs/bpf/Cargo.toml
|
||||
"$cargo" stable test --manifest-path programs/bpf/Cargo.toml
|
||||
"$cargo_build_bpf" --manifest-path programs/bpf/Cargo.toml --bpf-sdk sdk/bpf
|
||||
|
||||
# BPF program system tests
|
||||
@@ -75,7 +75,6 @@ test-stable-bpf)
|
||||
bpf_dump_archive="bpf-dumps.tar.bz2"
|
||||
rm -f "$bpf_dump_archive"
|
||||
tar cjvf "$bpf_dump_archive" "${bpf_target_path}"/{deploy/*.txt,bpfel-unknown-unknown/release/*.so}
|
||||
exit 0
|
||||
;;
|
||||
test-stable-perf)
|
||||
if [[ $(uname) = Linux ]]; then
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-clap-utils"
|
||||
version = "1.7.14"
|
||||
version = "1.6.28"
|
||||
description = "Solana utilities for the clap"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -12,8 +12,8 @@ edition = "2018"
|
||||
[dependencies]
|
||||
clap = "2.33.0"
|
||||
rpassword = "4.0"
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "=1.7.14" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.14" }
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "=1.6.28" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.28" }
|
||||
thiserror = "1.0.21"
|
||||
tiny-bip39 = "0.8.1"
|
||||
uriparse = "0.6.3"
|
||||
|
@@ -17,9 +17,6 @@ use {
|
||||
std::{str::FromStr, sync::Arc},
|
||||
};
|
||||
|
||||
// Sentinel value used to indicate to write to screen instead of file
|
||||
pub const STDOUT_OUTFILE_TOKEN: &str = "-";
|
||||
|
||||
// Return parsed values from matches at `name`
|
||||
pub fn values_of<T>(matches: &ArgMatches<'_>, name: &str) -> Option<Vec<T>>
|
||||
where
|
||||
|
@@ -1,6 +1,6 @@
|
||||
use {
|
||||
crate::{
|
||||
input_parsers::{pubkeys_sigs_of, STDOUT_OUTFILE_TOKEN},
|
||||
input_parsers::pubkeys_sigs_of,
|
||||
offline::{SIGNER_ARG, SIGN_ONLY_ARG},
|
||||
ArgConstant,
|
||||
},
|
||||
@@ -297,7 +297,7 @@ pub(crate) fn parse_signer_source<S: AsRef<str>>(
|
||||
}
|
||||
} else {
|
||||
match source.as_str() {
|
||||
STDOUT_OUTFILE_TOKEN => Ok(SignerSource::new(SignerSourceKind::Stdin)),
|
||||
"-" => Ok(SignerSource::new(SignerSourceKind::Stdin)),
|
||||
ASK_KEYWORD => Ok(SignerSource::new_legacy(SignerSourceKind::Prompt)),
|
||||
_ => match Pubkey::from_str(source.as_str()) {
|
||||
Ok(pubkey) => Ok(SignerSource::new(SignerSourceKind::Pubkey(pubkey))),
|
||||
@@ -506,7 +506,7 @@ pub const SKIP_SEED_PHRASE_VALIDATION_ARG: ArgConstant<'static> = ArgConstant {
|
||||
|
||||
/// Prompts user for a passphrase and then asks for confirmirmation to check for mistakes
|
||||
pub fn prompt_passphrase(prompt: &str) -> Result<String, Box<dyn error::Error>> {
|
||||
let passphrase = prompt_password_stderr(prompt)?;
|
||||
let passphrase = prompt_password_stderr(&prompt)?;
|
||||
if !passphrase.is_empty() {
|
||||
let confirmed = rpassword::prompt_password_stderr("Enter same passphrase again: ")?;
|
||||
if confirmed != passphrase {
|
||||
@@ -586,9 +586,9 @@ pub fn keypair_from_seed_phrase(
|
||||
let keypair = if skip_validation {
|
||||
let passphrase = prompt_passphrase(&passphrase_prompt)?;
|
||||
if legacy {
|
||||
keypair_from_seed_phrase_and_passphrase(seed_phrase, &passphrase)?
|
||||
keypair_from_seed_phrase_and_passphrase(&seed_phrase, &passphrase)?
|
||||
} else {
|
||||
let seed = generate_seed_from_seed_phrase_and_passphrase(seed_phrase, &passphrase);
|
||||
let seed = generate_seed_from_seed_phrase_and_passphrase(&seed_phrase, &passphrase);
|
||||
keypair_from_seed_and_derivation_path(&seed, derivation_path)?
|
||||
}
|
||||
} else {
|
||||
@@ -616,7 +616,7 @@ pub fn keypair_from_seed_phrase(
|
||||
if legacy {
|
||||
keypair_from_seed(seed.as_bytes())?
|
||||
} else {
|
||||
keypair_from_seed_and_derivation_path(seed.as_bytes(), derivation_path)?
|
||||
keypair_from_seed_and_derivation_path(&seed.as_bytes(), derivation_path)?
|
||||
}
|
||||
};
|
||||
|
||||
@@ -692,7 +692,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_parse_signer_source() {
|
||||
assert!(matches!(
|
||||
parse_signer_source(STDOUT_OUTFILE_TOKEN).unwrap(),
|
||||
parse_signer_source("-").unwrap(),
|
||||
SignerSource {
|
||||
kind: SignerSourceKind::Stdin,
|
||||
derivation_path: None,
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-cli-config"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.7.14"
|
||||
version = "1.6.28"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
|
@@ -107,24 +107,24 @@ mod test {
|
||||
#[test]
|
||||
fn compute_websocket_url() {
|
||||
assert_eq!(
|
||||
Config::compute_websocket_url("http://api.devnet.solana.com"),
|
||||
Config::compute_websocket_url(&"http://api.devnet.solana.com"),
|
||||
"ws://api.devnet.solana.com/".to_string()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Config::compute_websocket_url("https://api.devnet.solana.com"),
|
||||
Config::compute_websocket_url(&"https://api.devnet.solana.com"),
|
||||
"wss://api.devnet.solana.com/".to_string()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Config::compute_websocket_url("http://example.com:8899"),
|
||||
Config::compute_websocket_url(&"http://example.com:8899"),
|
||||
"ws://example.com:8900/".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
Config::compute_websocket_url("https://example.com:1234"),
|
||||
Config::compute_websocket_url(&"https://example.com:1234"),
|
||||
"wss://example.com:1235/".to_string()
|
||||
);
|
||||
|
||||
assert_eq!(Config::compute_websocket_url("garbage"), String::new());
|
||||
assert_eq!(Config::compute_websocket_url(&"garbage"), String::new());
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-cli-output"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.7.14"
|
||||
version = "1.6.28"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -12,20 +12,20 @@ documentation = "https://docs.rs/solana-cli-output"
|
||||
[dependencies]
|
||||
base64 = "0.13.0"
|
||||
chrono = { version = "0.4.11", features = ["serde"] }
|
||||
clap = "2.33.0"
|
||||
console = "0.14.1"
|
||||
console = "0.11.3"
|
||||
humantime = "2.0.1"
|
||||
Inflector = "0.11.4"
|
||||
indicatif = "0.15.0"
|
||||
serde = "1.0.122"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.56"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.7.14" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.7.14" }
|
||||
solana-client = { path = "../client", version = "=1.7.14" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.14" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.7.14" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.7.14" }
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.28" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.28" }
|
||||
solana-client = { path = "../client", version = "=1.6.28" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.28" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.28" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.28" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.28" }
|
||||
spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
|
@@ -8,7 +8,6 @@ use {
|
||||
QuietDisplay, VerboseDisplay,
|
||||
},
|
||||
chrono::{Local, TimeZone},
|
||||
clap::ArgMatches,
|
||||
console::{style, Emoji},
|
||||
inflector::cases::titlecase::to_title_case,
|
||||
serde::{Deserialize, Serialize},
|
||||
@@ -26,10 +25,10 @@ use {
|
||||
native_token::lamports_to_sol,
|
||||
pubkey::Pubkey,
|
||||
signature::Signature,
|
||||
stake::state::{Authorized, Lockup},
|
||||
stake_history::StakeHistoryEntry,
|
||||
transaction::{Transaction, TransactionError},
|
||||
},
|
||||
solana_stake_program::stake_state::{Authorized, Lockup},
|
||||
solana_transaction_status::{
|
||||
EncodedConfirmedBlock, EncodedTransaction, TransactionConfirmationStatus,
|
||||
UiTransactionStatusMeta,
|
||||
@@ -48,7 +47,7 @@ use {
|
||||
|
||||
static WARNING: Emoji = Emoji("⚠️", "!");
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
#[derive(PartialEq)]
|
||||
pub enum OutputFormat {
|
||||
Display,
|
||||
Json,
|
||||
@@ -78,21 +77,6 @@ impl OutputFormat {
|
||||
OutputFormat::JsonCompact => serde_json::to_value(item).unwrap().to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_matches(matches: &ArgMatches<'_>, output_name: &str, verbose: bool) -> Self {
|
||||
matches
|
||||
.value_of(output_name)
|
||||
.map(|value| match value {
|
||||
"json" => OutputFormat::Json,
|
||||
"json-compact" => OutputFormat::JsonCompact,
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.unwrap_or(if verbose {
|
||||
OutputFormat::DisplayVerbose
|
||||
} else {
|
||||
OutputFormat::Display
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@@ -1350,7 +1334,7 @@ impl fmt::Display for CliValidatorInfo {
|
||||
writeln_name_value(
|
||||
f,
|
||||
&format!(" {}:", to_title_case(key)),
|
||||
value.as_str().unwrap_or("?"),
|
||||
&value.as_str().unwrap_or("?"),
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
@@ -1388,8 +1372,8 @@ impl fmt::Display for CliVoteAccount {
|
||||
build_balance_message(self.account_balance, self.use_lamports_unit, true)
|
||||
)?;
|
||||
writeln!(f, "Validator Identity: {}", self.validator_identity)?;
|
||||
writeln!(f, "Vote Authority: {}", self.authorized_voters)?;
|
||||
writeln!(f, "Withdraw Authority: {}", self.authorized_withdrawer)?;
|
||||
writeln!(f, "Authorized Voters: {}", self.authorized_voters)?;
|
||||
writeln!(f, "Authorized Withdrawer: {}", self.authorized_withdrawer)?;
|
||||
writeln!(f, "Credits: {}", self.credits)?;
|
||||
writeln!(f, "Commission: {}%", self.commission)?;
|
||||
writeln!(
|
||||
@@ -1576,19 +1560,15 @@ impl fmt::Display for CliInflation {
|
||||
"Staking rate: {:>5.2}%",
|
||||
self.current_rate.validator * 100.
|
||||
)?;
|
||||
|
||||
if self.current_rate.foundation > 0. {
|
||||
writeln!(
|
||||
f,
|
||||
"Foundation rate: {:>5.2}%",
|
||||
self.current_rate.foundation * 100.
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
writeln!(
|
||||
f,
|
||||
"Foundation rate: {:>5.2}%",
|
||||
self.current_rate.foundation * 100.
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Default, Debug, PartialEq)]
|
||||
#[derive(Serialize, Deserialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CliSignOnlyData {
|
||||
pub blockhash: String,
|
||||
@@ -1838,7 +1818,7 @@ impl fmt::Display for CliTokenAccount {
|
||||
writeln_name_value(
|
||||
f,
|
||||
"Close authority:",
|
||||
account.close_authority.as_ref().unwrap_or(&String::new()),
|
||||
&account.close_authority.as_ref().unwrap_or(&String::new()),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -1930,9 +1910,6 @@ pub struct CliUpgradeableProgram {
|
||||
pub authority: String,
|
||||
pub last_deploy_slot: u64,
|
||||
pub data_len: usize,
|
||||
pub lamports: u64,
|
||||
#[serde(skip_serializing)]
|
||||
pub use_lamports_unit: bool,
|
||||
}
|
||||
impl QuietDisplay for CliUpgradeableProgram {}
|
||||
impl VerboseDisplay for CliUpgradeableProgram {}
|
||||
@@ -1953,78 +1930,12 @@ impl fmt::Display for CliUpgradeableProgram {
|
||||
"Data Length:",
|
||||
&format!("{:?} ({:#x?}) bytes", self.data_len, self.data_len),
|
||||
)?;
|
||||
writeln_name_value(
|
||||
f,
|
||||
"Balance:",
|
||||
&build_balance_message(self.lamports, self.use_lamports_unit, true),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CliUpgradeablePrograms {
|
||||
pub programs: Vec<CliUpgradeableProgram>,
|
||||
#[serde(skip_serializing)]
|
||||
pub use_lamports_unit: bool,
|
||||
}
|
||||
impl QuietDisplay for CliUpgradeablePrograms {}
|
||||
impl VerboseDisplay for CliUpgradeablePrograms {}
|
||||
impl fmt::Display for CliUpgradeablePrograms {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
writeln!(f)?;
|
||||
writeln!(
|
||||
f,
|
||||
"{}",
|
||||
style(format!(
|
||||
"{:<44} | {:<9} | {:<44} | {}",
|
||||
"Program Id", "Slot", "Authority", "Balance"
|
||||
))
|
||||
.bold()
|
||||
)?;
|
||||
for program in self.programs.iter() {
|
||||
writeln!(
|
||||
f,
|
||||
"{}",
|
||||
&format!(
|
||||
"{:<44} | {:<9} | {:<44} | {}",
|
||||
program.program_id,
|
||||
program.last_deploy_slot,
|
||||
program.authority,
|
||||
build_balance_message(program.lamports, self.use_lamports_unit, true)
|
||||
)
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CliUpgradeableProgramClosed {
|
||||
pub program_id: String,
|
||||
pub lamports: u64,
|
||||
#[serde(skip_serializing)]
|
||||
pub use_lamports_unit: bool,
|
||||
}
|
||||
impl QuietDisplay for CliUpgradeableProgramClosed {}
|
||||
impl VerboseDisplay for CliUpgradeableProgramClosed {}
|
||||
impl fmt::Display for CliUpgradeableProgramClosed {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
writeln!(f)?;
|
||||
writeln!(
|
||||
f,
|
||||
"Closed Program Id {}, {} reclaimed",
|
||||
&self.program_id,
|
||||
&build_balance_message(self.lamports, self.use_lamports_unit, true)
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CliUpgradeableBuffer {
|
||||
pub address: String,
|
||||
pub authority: String,
|
||||
@@ -2109,11 +2020,6 @@ pub fn return_signers_with_config(
|
||||
output_format: &OutputFormat,
|
||||
config: &ReturnSignersConfig,
|
||||
) -> Result<String, Box<dyn std::error::Error>> {
|
||||
let cli_command = return_signers_data(tx, config);
|
||||
Ok(output_format.formatted_string(&cli_command))
|
||||
}
|
||||
|
||||
pub fn return_signers_data(tx: &Transaction, config: &ReturnSignersConfig) -> CliSignOnlyData {
|
||||
let verify_results = tx.verify_with_results();
|
||||
let mut signers = Vec::new();
|
||||
let mut absent = Vec::new();
|
||||
@@ -2138,17 +2044,19 @@ pub fn return_signers_data(tx: &Transaction, config: &ReturnSignersConfig) -> Cl
|
||||
None
|
||||
};
|
||||
|
||||
CliSignOnlyData {
|
||||
let cli_command = CliSignOnlyData {
|
||||
blockhash: tx.message.recent_blockhash.to_string(),
|
||||
message,
|
||||
signers,
|
||||
absent,
|
||||
bad_sig,
|
||||
}
|
||||
};
|
||||
|
||||
Ok(output_format.formatted_string(&cli_command))
|
||||
}
|
||||
|
||||
pub fn parse_sign_only_reply_string(reply: &str) -> SignOnly {
|
||||
let object: Value = serde_json::from_str(reply).unwrap();
|
||||
let object: Value = serde_json::from_str(&reply).unwrap();
|
||||
let blockhash_str = object.get("blockhash").unwrap().as_str().unwrap();
|
||||
let blockhash = blockhash_str.parse::<Hash>().unwrap();
|
||||
let mut present_signers: Vec<(Pubkey, Signature)> = Vec::new();
|
||||
@@ -2526,7 +2434,6 @@ impl VerboseDisplay for CliGossipNodes {}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use clap::{App, Arg};
|
||||
use solana_sdk::{
|
||||
message::Message,
|
||||
pubkey::Pubkey,
|
||||
@@ -2587,22 +2494,6 @@ mod tests {
|
||||
assert_eq!(sign_only.absent_signers[0], absent.pubkey());
|
||||
assert_eq!(sign_only.bad_signers[0], bad.pubkey());
|
||||
|
||||
let res_data = return_signers_data(&tx, &ReturnSignersConfig::default());
|
||||
assert_eq!(
|
||||
res_data,
|
||||
CliSignOnlyData {
|
||||
blockhash: blockhash.to_string(),
|
||||
message: None,
|
||||
signers: vec![format!(
|
||||
"{}={}",
|
||||
present.pubkey().to_string(),
|
||||
tx.signatures[1]
|
||||
)],
|
||||
absent: vec![absent.pubkey().to_string()],
|
||||
bad_sig: vec![bad.pubkey().to_string()],
|
||||
}
|
||||
);
|
||||
|
||||
let expected_msg = "AwECBwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDgTl3Dqh9\
|
||||
F19Wo1Rmw0x+zMuNipG07jeiXfYPW4/Js5QEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE\
|
||||
BAQEBAYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBQUFBQUFBQUFBQUFBQUFBQUF\
|
||||
@@ -2616,26 +2507,10 @@ mod tests {
|
||||
let res = return_signers_with_config(&tx, &OutputFormat::JsonCompact, &config).unwrap();
|
||||
let sign_only = parse_sign_only_reply_string(&res);
|
||||
assert_eq!(sign_only.blockhash, blockhash);
|
||||
assert_eq!(sign_only.message, Some(expected_msg.clone()));
|
||||
assert_eq!(sign_only.message, Some(expected_msg));
|
||||
assert_eq!(sign_only.present_signers[0].0, present.pubkey());
|
||||
assert_eq!(sign_only.absent_signers[0], absent.pubkey());
|
||||
assert_eq!(sign_only.bad_signers[0], bad.pubkey());
|
||||
|
||||
let res_data = return_signers_data(&tx, &config);
|
||||
assert_eq!(
|
||||
res_data,
|
||||
CliSignOnlyData {
|
||||
blockhash: blockhash.to_string(),
|
||||
message: Some(expected_msg),
|
||||
signers: vec![format!(
|
||||
"{}={}",
|
||||
present.pubkey().to_string(),
|
||||
tx.signatures[1]
|
||||
)],
|
||||
absent: vec![absent.pubkey().to_string()],
|
||||
bad_sig: vec![bad.pubkey().to_string()],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -2684,50 +2559,4 @@ mod tests {
|
||||
"verbose"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_output_format_from_matches() {
|
||||
let app = App::new("test").arg(
|
||||
Arg::with_name("output_format")
|
||||
.long("output")
|
||||
.value_name("FORMAT")
|
||||
.global(true)
|
||||
.takes_value(true)
|
||||
.possible_values(&["json", "json-compact"])
|
||||
.help("Return information in specified output format"),
|
||||
);
|
||||
let matches = app
|
||||
.clone()
|
||||
.get_matches_from(vec!["test", "--output", "json"]);
|
||||
assert_eq!(
|
||||
OutputFormat::from_matches(&matches, "output_format", false),
|
||||
OutputFormat::Json
|
||||
);
|
||||
assert_eq!(
|
||||
OutputFormat::from_matches(&matches, "output_format", true),
|
||||
OutputFormat::Json
|
||||
);
|
||||
|
||||
let matches = app
|
||||
.clone()
|
||||
.get_matches_from(vec!["test", "--output", "json-compact"]);
|
||||
assert_eq!(
|
||||
OutputFormat::from_matches(&matches, "output_format", false),
|
||||
OutputFormat::JsonCompact
|
||||
);
|
||||
assert_eq!(
|
||||
OutputFormat::from_matches(&matches, "output_format", true),
|
||||
OutputFormat::JsonCompact
|
||||
);
|
||||
|
||||
let matches = app.clone().get_matches_from(vec!["test"]);
|
||||
assert_eq!(
|
||||
OutputFormat::from_matches(&matches, "output_format", false),
|
||||
OutputFormat::Display
|
||||
);
|
||||
assert_eq!(
|
||||
OutputFormat::from_matches(&matches, "output_format", true),
|
||||
OutputFormat::DisplayVerbose
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ use {
|
||||
indicatif::{ProgressBar, ProgressStyle},
|
||||
solana_sdk::{
|
||||
clock::UnixTimestamp, hash::Hash, message::Message, native_token::lamports_to_sol,
|
||||
program_utils::limited_deserialize, pubkey::Pubkey, stake, transaction::Transaction,
|
||||
program_utils::limited_deserialize, pubkey::Pubkey, transaction::Transaction,
|
||||
},
|
||||
solana_transaction_status::UiTransactionStatusMeta,
|
||||
spl_memo::id as spl_memo_id,
|
||||
@@ -140,7 +140,7 @@ fn format_account_mode(message: &Message, index: usize) -> String {
|
||||
} else {
|
||||
"-"
|
||||
},
|
||||
if message.is_writable(index, /*demote_program_write_locks=*/ true) {
|
||||
if message.is_writable(index, /* demote_program_write_locks=*/ true) {
|
||||
"w" // comment for consistent rust fmt (no joking; lol)
|
||||
} else {
|
||||
"-"
|
||||
@@ -244,9 +244,10 @@ pub fn write_transaction<W: io::Write>(
|
||||
writeln!(w, "{} {:?}", prefix, vote_instruction)?;
|
||||
raw = false;
|
||||
}
|
||||
} else if program_pubkey == stake::program::id() {
|
||||
if let Ok(stake_instruction) =
|
||||
limited_deserialize::<stake::instruction::StakeInstruction>(&instruction.data)
|
||||
} else if program_pubkey == solana_stake_program::id() {
|
||||
if let Ok(stake_instruction) = limited_deserialize::<
|
||||
solana_stake_program::stake_instruction::StakeInstruction,
|
||||
>(&instruction.data)
|
||||
{
|
||||
writeln!(w, "{} {:?}", prefix, stake_instruction)?;
|
||||
raw = false;
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-cli"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.7.14"
|
||||
version = "1.6.28"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -16,7 +16,7 @@ chrono = { version = "0.4.11", features = ["serde"] }
|
||||
clap = "2.33.1"
|
||||
criterion-stats = "0.3.0"
|
||||
ctrlc = { version = "3.1.5", features = ["termination"] }
|
||||
console = "0.14.1"
|
||||
console = "0.11.3"
|
||||
const_format = "0.2.14"
|
||||
dirs-next = "2.0.0"
|
||||
log = "0.4.11"
|
||||
@@ -29,30 +29,30 @@ reqwest = { version = "0.11.2", default-features = false, features = ["blocking"
|
||||
serde = "1.0.122"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.56"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.7.14" }
|
||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "=1.7.14" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.7.14" }
|
||||
solana-cli-config = { path = "../cli-config", version = "=1.7.14" }
|
||||
solana-cli-output = { path = "../cli-output", version = "=1.7.14" }
|
||||
solana-client = { path = "../client", version = "=1.7.14" }
|
||||
solana-config-program = { path = "../programs/config", version = "=1.7.14" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.7.14" }
|
||||
solana-logger = { path = "../logger", version = "=1.7.14" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.7.14" }
|
||||
solana_rbpf = "=0.2.11"
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "=1.7.14" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.14" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.7.14" }
|
||||
solana-version = { path = "../version", version = "=1.7.14" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.7.14" }
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.28" }
|
||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "=1.6.28" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.28" }
|
||||
solana-cli-config = { path = "../cli-config", version = "=1.6.28" }
|
||||
solana-cli-output = { path = "../cli-output", version = "=1.6.28" }
|
||||
solana-client = { path = "../client", version = "=1.6.28" }
|
||||
solana-config-program = { path = "../programs/config", version = "=1.6.28" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.28" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.28" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.28" }
|
||||
solana_rbpf = "=0.2.9"
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "=1.6.28" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.28" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.28" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.28" }
|
||||
solana-version = { path = "../version", version = "=1.6.28" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.28" }
|
||||
spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] }
|
||||
thiserror = "1.0.21"
|
||||
tiny-bip39 = "0.8.1"
|
||||
url = "2.1.1"
|
||||
|
||||
[dev-dependencies]
|
||||
solana-core = { path = "../core", version = "=1.7.14" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.7.14" }
|
||||
solana-core = { path = "../core", version = "=1.6.28" }
|
||||
tempfile = "3.1.0"
|
||||
|
||||
[[bin]]
|
||||
|
@@ -231,9 +231,18 @@ mod tests {
|
||||
mocks.insert(RpcRequest::GetBalance, account_balance_response);
|
||||
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
|
||||
|
||||
assert!(check_account_for_balance(&rpc_client, &pubkey, 1).unwrap());
|
||||
assert!(check_account_for_balance(&rpc_client, &pubkey, account_balance).unwrap());
|
||||
assert!(!check_account_for_balance(&rpc_client, &pubkey, account_balance + 1).unwrap());
|
||||
assert_eq!(
|
||||
check_account_for_balance(&rpc_client, &pubkey, 1).unwrap(),
|
||||
true
|
||||
);
|
||||
assert_eq!(
|
||||
check_account_for_balance(&rpc_client, &pubkey, account_balance).unwrap(),
|
||||
true
|
||||
);
|
||||
assert_eq!(
|
||||
check_account_for_balance(&rpc_client, &pubkey, account_balance + 1).unwrap(),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@@ -1,202 +0,0 @@
|
||||
use crate::{
|
||||
cli::*, cluster_query::*, feature::*, inflation::*, nonce::*, program::*, stake::*,
|
||||
validator_info::*, vote::*, wallet::*,
|
||||
};
|
||||
use clap::{App, AppSettings, Arg, ArgGroup, SubCommand};
|
||||
use solana_clap_utils::{self, input_validators::*, keypair::*};
|
||||
use solana_cli_config::CONFIG_FILE;
|
||||
|
||||
pub fn get_clap_app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, 'v> {
|
||||
App::new(name)
|
||||
.about(about)
|
||||
.version(version)
|
||||
.setting(AppSettings::SubcommandRequiredElseHelp)
|
||||
.arg({
|
||||
let arg = Arg::with_name("config_file")
|
||||
.short("C")
|
||||
.long("config")
|
||||
.value_name("FILEPATH")
|
||||
.takes_value(true)
|
||||
.global(true)
|
||||
.help("Configuration file to use");
|
||||
if let Some(ref config_file) = *CONFIG_FILE {
|
||||
arg.default_value(config_file)
|
||||
} else {
|
||||
arg
|
||||
}
|
||||
})
|
||||
.arg(
|
||||
Arg::with_name("json_rpc_url")
|
||||
.short("u")
|
||||
.long("url")
|
||||
.value_name("URL_OR_MONIKER")
|
||||
.takes_value(true)
|
||||
.global(true)
|
||||
.validator(is_url_or_moniker)
|
||||
.help(
|
||||
"URL for Solana's JSON RPC or moniker (or their first letter): \
|
||||
[mainnet-beta, testnet, devnet, localhost]",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("websocket_url")
|
||||
.long("ws")
|
||||
.value_name("URL")
|
||||
.takes_value(true)
|
||||
.global(true)
|
||||
.validator(is_url)
|
||||
.help("WebSocket URL for the solana cluster"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("keypair")
|
||||
.short("k")
|
||||
.long("keypair")
|
||||
.value_name("KEYPAIR")
|
||||
.global(true)
|
||||
.takes_value(true)
|
||||
.help("Filepath or URL to a keypair"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("commitment")
|
||||
.long("commitment")
|
||||
.takes_value(true)
|
||||
.possible_values(&[
|
||||
"processed",
|
||||
"confirmed",
|
||||
"finalized",
|
||||
"recent", // Deprecated as of v1.5.5
|
||||
"single", // Deprecated as of v1.5.5
|
||||
"singleGossip", // Deprecated as of v1.5.5
|
||||
"root", // Deprecated as of v1.5.5
|
||||
"max", // Deprecated as of v1.5.5
|
||||
])
|
||||
.value_name("COMMITMENT_LEVEL")
|
||||
.hide_possible_values(true)
|
||||
.global(true)
|
||||
.help("Return information at the selected commitment level [possible values: processed, confirmed, finalized]"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("verbose")
|
||||
.long("verbose")
|
||||
.short("v")
|
||||
.global(true)
|
||||
.help("Show additional information"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("no_address_labels")
|
||||
.long("no-address-labels")
|
||||
.global(true)
|
||||
.help("Do not use address labels in the output"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("output_format")
|
||||
.long("output")
|
||||
.value_name("FORMAT")
|
||||
.global(true)
|
||||
.takes_value(true)
|
||||
.possible_values(&["json", "json-compact"])
|
||||
.help("Return information in specified output format"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(SKIP_SEED_PHRASE_VALIDATION_ARG.name)
|
||||
.long(SKIP_SEED_PHRASE_VALIDATION_ARG.long)
|
||||
.global(true)
|
||||
.help(SKIP_SEED_PHRASE_VALIDATION_ARG.help),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("rpc_timeout")
|
||||
.long("rpc-timeout")
|
||||
.value_name("SECONDS")
|
||||
.takes_value(true)
|
||||
.default_value(DEFAULT_RPC_TIMEOUT_SECONDS)
|
||||
.global(true)
|
||||
.hidden(true)
|
||||
.help("Timeout value for RPC requests"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("confirm_transaction_initial_timeout")
|
||||
.long("confirm-timeout")
|
||||
.value_name("SECONDS")
|
||||
.takes_value(true)
|
||||
.default_value(DEFAULT_CONFIRM_TX_TIMEOUT_SECONDS)
|
||||
.global(true)
|
||||
.hidden(true)
|
||||
.help("Timeout value for initial transaction status"),
|
||||
)
|
||||
.cluster_query_subcommands()
|
||||
.feature_subcommands()
|
||||
.inflation_subcommands()
|
||||
.nonce_subcommands()
|
||||
.program_subcommands()
|
||||
.stake_subcommands()
|
||||
.validator_info_subcommands()
|
||||
.vote_subcommands()
|
||||
.wallet_subcommands()
|
||||
.subcommand(
|
||||
SubCommand::with_name("config")
|
||||
.about("Solana command-line tool configuration settings")
|
||||
.aliases(&["get", "set"])
|
||||
.setting(AppSettings::SubcommandRequiredElseHelp)
|
||||
.subcommand(
|
||||
SubCommand::with_name("get")
|
||||
.about("Get current config settings")
|
||||
.arg(
|
||||
Arg::with_name("specific_setting")
|
||||
.index(1)
|
||||
.value_name("CONFIG_FIELD")
|
||||
.takes_value(true)
|
||||
.possible_values(&[
|
||||
"json_rpc_url",
|
||||
"websocket_url",
|
||||
"keypair",
|
||||
"commitment",
|
||||
])
|
||||
.help("Return a specific config setting"),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("set")
|
||||
.about("Set a config setting")
|
||||
.group(
|
||||
ArgGroup::with_name("config_settings")
|
||||
.args(&["json_rpc_url", "websocket_url", "keypair", "commitment"])
|
||||
.multiple(true)
|
||||
.required(true),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("import-address-labels")
|
||||
.about("Import a list of address labels")
|
||||
.arg(
|
||||
Arg::with_name("filename")
|
||||
.index(1)
|
||||
.value_name("FILENAME")
|
||||
.takes_value(true)
|
||||
.help("YAML file of address labels"),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("export-address-labels")
|
||||
.about("Export the current address labels")
|
||||
.arg(
|
||||
Arg::with_name("filename")
|
||||
.index(1)
|
||||
.value_name("FILENAME")
|
||||
.takes_value(true)
|
||||
.help("YAML file to receive the current address labels"),
|
||||
),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("completion")
|
||||
.about("Generate completion scripts for various shells")
|
||||
.arg(
|
||||
Arg::with_name("shell")
|
||||
.long("shell")
|
||||
.short("s")
|
||||
.takes_value(true)
|
||||
.possible_values(&["bash", "fish", "zsh", "powershell", "elvish"])
|
||||
.default_value("bash")
|
||||
)
|
||||
)
|
||||
}
|
1029
cli/src/cli.rs
1029
cli/src/cli.rs
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
use crate::{
|
||||
cli::{CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult},
|
||||
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
|
||||
stake::is_stake_program_v2_enabled,
|
||||
};
|
||||
use clap::{value_t, value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand};
|
||||
use console::{style, Emoji};
|
||||
@@ -23,9 +24,9 @@ use solana_client::{
|
||||
pubsub_client::PubsubClient,
|
||||
rpc_client::{GetConfirmedSignaturesForAddress2Config, RpcClient},
|
||||
rpc_config::{
|
||||
RpcAccountInfoConfig, RpcBlockConfig, RpcGetVoteAccountsConfig, RpcLargestAccountsConfig,
|
||||
RpcLargestAccountsFilter, RpcProgramAccountsConfig, RpcTransactionConfig,
|
||||
RpcTransactionLogsConfig, RpcTransactionLogsFilter,
|
||||
RpcAccountInfoConfig, RpcConfirmedBlockConfig, RpcConfirmedTransactionConfig,
|
||||
RpcGetVoteAccountsConfig, RpcLargestAccountsConfig, RpcLargestAccountsFilter,
|
||||
RpcProgramAccountsConfig, RpcTransactionLogsConfig, RpcTransactionLogsFilter,
|
||||
},
|
||||
rpc_filter,
|
||||
rpc_request::DELINQUENT_VALIDATOR_SLOT_DISTANCE,
|
||||
@@ -46,9 +47,7 @@ use solana_sdk::{
|
||||
rent::Rent,
|
||||
rpc_port::DEFAULT_RPC_PORT_STR,
|
||||
signature::Signature,
|
||||
slot_history,
|
||||
stake::{self, state::StakeState},
|
||||
system_instruction, system_program,
|
||||
slot_history, system_instruction, system_program,
|
||||
sysvar::{
|
||||
self,
|
||||
slot_history::SlotHistory,
|
||||
@@ -57,6 +56,7 @@ use solana_sdk::{
|
||||
timing,
|
||||
transaction::Transaction,
|
||||
};
|
||||
use solana_stake_program::stake_state::StakeState;
|
||||
use solana_transaction_status::UiTransactionEncoding;
|
||||
use solana_vote_program::vote_state::VoteState;
|
||||
use std::{
|
||||
@@ -122,7 +122,7 @@ impl ClusterQuerySubCommands for App<'_, '_> {
|
||||
.long("our-localhost")
|
||||
.takes_value(false)
|
||||
.value_name("PORT")
|
||||
.default_value(DEFAULT_RPC_PORT_STR)
|
||||
.default_value(&DEFAULT_RPC_PORT_STR)
|
||||
.validator(is_port)
|
||||
.help("Guess Identity pubkey and validator rpc node assuming local (possibly private) validator"),
|
||||
)
|
||||
@@ -1052,12 +1052,12 @@ pub fn process_get_block(
|
||||
};
|
||||
|
||||
let encoded_confirmed_block = rpc_client
|
||||
.get_block_with_config(
|
||||
.get_confirmed_block_with_config(
|
||||
slot,
|
||||
RpcBlockConfig {
|
||||
RpcConfirmedBlockConfig {
|
||||
encoding: Some(UiTransactionEncoding::Base64),
|
||||
commitment: Some(CommitmentConfig::confirmed()),
|
||||
..RpcBlockConfig::default()
|
||||
..RpcConfirmedBlockConfig::default()
|
||||
},
|
||||
)?
|
||||
.into();
|
||||
@@ -1215,7 +1215,7 @@ pub fn process_show_block_production(
|
||||
start_slot = minimum_ledger_slot;
|
||||
}
|
||||
|
||||
let confirmed_blocks = rpc_client.get_blocks(start_slot, Some(end_slot))?;
|
||||
let confirmed_blocks = rpc_client.get_confirmed_blocks(start_slot, Some(end_slot))?;
|
||||
(confirmed_blocks, start_slot)
|
||||
};
|
||||
|
||||
@@ -1738,7 +1738,7 @@ pub fn process_show_stakes(
|
||||
}
|
||||
}
|
||||
let all_stake_accounts = rpc_client
|
||||
.get_program_accounts_with_config(&stake::program::id(), program_accounts_config)?;
|
||||
.get_program_accounts_with_config(&solana_stake_program::id(), program_accounts_config)?;
|
||||
let stake_history_account = rpc_client.get_account(&stake_history::id())?;
|
||||
let clock_account = rpc_client.get_account(&sysvar::clock::id())?;
|
||||
let clock: Clock = from_account(&clock_account).ok_or_else(|| {
|
||||
@@ -1749,6 +1749,8 @@ pub fn process_show_stakes(
|
||||
let stake_history = from_account(&stake_history_account).ok_or_else(|| {
|
||||
CliError::RpcRequestError("Failed to deserialize stake history".to_string())
|
||||
})?;
|
||||
// At v1.6, this check can be removed and simply passed as `true`
|
||||
let stake_program_v2_enabled = is_stake_program_v2_enabled(rpc_client)?;
|
||||
|
||||
let mut stake_accounts: Vec<CliKeyedStakeState> = vec![];
|
||||
for (stake_pubkey, stake_account) in all_stake_accounts {
|
||||
@@ -1764,6 +1766,7 @@ pub fn process_show_stakes(
|
||||
use_lamports_unit,
|
||||
&stake_history,
|
||||
&clock,
|
||||
stake_program_v2_enabled,
|
||||
),
|
||||
});
|
||||
}
|
||||
@@ -1782,6 +1785,7 @@ pub fn process_show_stakes(
|
||||
use_lamports_unit,
|
||||
&stake_history,
|
||||
&clock,
|
||||
stake_program_v2_enabled,
|
||||
),
|
||||
});
|
||||
}
|
||||
@@ -1973,7 +1977,7 @@ pub fn process_transaction_history(
|
||||
limit: usize,
|
||||
show_transactions: bool,
|
||||
) -> ProcessResult {
|
||||
let results = rpc_client.get_signatures_for_address_with_config(
|
||||
let results = rpc_client.get_confirmed_signatures_for_address2_with_config(
|
||||
address,
|
||||
GetConfirmedSignaturesForAddress2Config {
|
||||
before,
|
||||
@@ -2012,9 +2016,9 @@ pub fn process_transaction_history(
|
||||
|
||||
if show_transactions {
|
||||
if let Ok(signature) = result.signature.parse::<Signature>() {
|
||||
match rpc_client.get_transaction_with_config(
|
||||
match rpc_client.get_confirmed_transaction_with_config(
|
||||
&signature,
|
||||
RpcTransactionConfig {
|
||||
RpcConfirmedTransactionConfig {
|
||||
encoding: Some(UiTransactionEncoding::Base64),
|
||||
commitment: Some(CommitmentConfig::confirmed()),
|
||||
},
|
||||
@@ -2141,7 +2145,7 @@ pub fn process_calculate_rent(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{clap_app::get_clap_app, cli::parse_command};
|
||||
use crate::cli::{app, parse_command};
|
||||
use solana_sdk::signature::{write_keypair, Keypair};
|
||||
use std::str::FromStr;
|
||||
use tempfile::NamedTempFile;
|
||||
@@ -2153,7 +2157,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_parse_command() {
|
||||
let test_commands = get_clap_app("test", "desc", "version");
|
||||
let test_commands = app("test", "desc", "version");
|
||||
let default_keypair = Keypair::new();
|
||||
let (default_keypair_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
|
@@ -102,7 +102,7 @@ fn process_rewards(
|
||||
rewards_epoch: Option<Epoch>,
|
||||
) -> ProcessResult {
|
||||
let rewards = rpc_client
|
||||
.get_inflation_reward(addresses, rewards_epoch)
|
||||
.get_inflation_reward(&addresses, rewards_epoch)
|
||||
.map_err(|err| {
|
||||
if let Some(epoch) = rewards_epoch {
|
||||
format!("Rewards not available for epoch {}", epoch)
|
||||
|
@@ -10,6 +10,7 @@ macro_rules! ACCOUNT_STRING {
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_use]
|
||||
macro_rules! pubkey {
|
||||
($arg:expr, $help:expr) => {
|
||||
$arg.takes_value(true)
|
||||
@@ -24,7 +25,6 @@ extern crate const_format;
|
||||
extern crate serde_derive;
|
||||
|
||||
pub mod checks;
|
||||
pub mod clap_app;
|
||||
pub mod cli;
|
||||
pub mod cluster_query;
|
||||
pub mod feature;
|
||||
@@ -37,4 +37,3 @@ pub mod stake;
|
||||
pub mod test_utils;
|
||||
pub mod validator_info;
|
||||
pub mod vote;
|
||||
pub mod wallet;
|
||||
|
205
cli/src/main.rs
205
cli/src/main.rs
@@ -1,15 +1,18 @@
|
||||
use clap::{crate_description, crate_name, value_t_or_exit, ArgMatches};
|
||||
use clap::{
|
||||
crate_description, crate_name, value_t_or_exit, AppSettings, Arg, ArgGroup, ArgMatches,
|
||||
SubCommand,
|
||||
};
|
||||
use console::style;
|
||||
use solana_clap_utils::{
|
||||
input_validators::normalize_to_url_if_moniker,
|
||||
keypair::{CliSigners, DefaultSigner},
|
||||
input_validators::{is_url, is_url_or_moniker, normalize_to_url_if_moniker},
|
||||
keypair::{CliSigners, DefaultSigner, SKIP_SEED_PHRASE_VALIDATION_ARG},
|
||||
DisplayError,
|
||||
};
|
||||
use solana_cli::{
|
||||
clap_app::get_clap_app,
|
||||
cli::{parse_command, process_command, CliCommandInfo, CliConfig, SettingType},
|
||||
use solana_cli::cli::{
|
||||
app, parse_command, process_command, CliCommandInfo, CliConfig, SettingType,
|
||||
DEFAULT_CONFIRM_TX_TIMEOUT_SECONDS, DEFAULT_RPC_TIMEOUT_SECONDS,
|
||||
};
|
||||
use solana_cli_config::Config;
|
||||
use solana_cli_config::{Config, CONFIG_FILE};
|
||||
use solana_cli_output::{display::println_name_value, OutputFormat};
|
||||
use solana_client::rpc_config::RpcSendTransactionConfig;
|
||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||
@@ -186,7 +189,7 @@ pub fn parse_args<'a>(
|
||||
let CliCommandInfo {
|
||||
command,
|
||||
mut signers,
|
||||
} = parse_command(matches, &default_signer, &mut wallet_manager)?;
|
||||
} = parse_command(&matches, &default_signer, &mut wallet_manager)?;
|
||||
|
||||
if signers.is_empty() {
|
||||
if let Ok(signer_info) =
|
||||
@@ -197,7 +200,18 @@ pub fn parse_args<'a>(
|
||||
}
|
||||
|
||||
let verbose = matches.is_present("verbose");
|
||||
let output_format = OutputFormat::from_matches(matches, "output_format", verbose);
|
||||
let output_format = matches
|
||||
.value_of("output_format")
|
||||
.map(|value| match value {
|
||||
"json" => OutputFormat::Json,
|
||||
"json-compact" => OutputFormat::JsonCompact,
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.unwrap_or(if verbose {
|
||||
OutputFormat::DisplayVerbose
|
||||
} else {
|
||||
OutputFormat::Display
|
||||
});
|
||||
|
||||
let (_, commitment) = CliConfig::compute_commitment_config(
|
||||
matches.value_of("commitment").unwrap_or(""),
|
||||
@@ -235,21 +249,188 @@ pub fn parse_args<'a>(
|
||||
|
||||
fn main() -> Result<(), Box<dyn error::Error>> {
|
||||
solana_logger::setup_with_default("off");
|
||||
let matches = get_clap_app(
|
||||
let matches = app(
|
||||
crate_name!(),
|
||||
crate_description!(),
|
||||
solana_version::version!(),
|
||||
)
|
||||
.arg({
|
||||
let arg = Arg::with_name("config_file")
|
||||
.short("C")
|
||||
.long("config")
|
||||
.value_name("FILEPATH")
|
||||
.takes_value(true)
|
||||
.global(true)
|
||||
.help("Configuration file to use");
|
||||
if let Some(ref config_file) = *CONFIG_FILE {
|
||||
arg.default_value(&config_file)
|
||||
} else {
|
||||
arg
|
||||
}
|
||||
})
|
||||
.arg(
|
||||
Arg::with_name("json_rpc_url")
|
||||
.short("u")
|
||||
.long("url")
|
||||
.value_name("URL_OR_MONIKER")
|
||||
.takes_value(true)
|
||||
.global(true)
|
||||
.validator(is_url_or_moniker)
|
||||
.help(
|
||||
"URL for Solana's JSON RPC or moniker (or their first letter): \
|
||||
[mainnet-beta, testnet, devnet, localhost]",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("websocket_url")
|
||||
.long("ws")
|
||||
.value_name("URL")
|
||||
.takes_value(true)
|
||||
.global(true)
|
||||
.validator(is_url)
|
||||
.help("WebSocket URL for the solana cluster"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("keypair")
|
||||
.short("k")
|
||||
.long("keypair")
|
||||
.value_name("KEYPAIR")
|
||||
.global(true)
|
||||
.takes_value(true)
|
||||
.help("Filepath or URL to a keypair"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("commitment")
|
||||
.long("commitment")
|
||||
.takes_value(true)
|
||||
.possible_values(&[
|
||||
"processed",
|
||||
"confirmed",
|
||||
"finalized",
|
||||
"recent", // Deprecated as of v1.5.5
|
||||
"single", // Deprecated as of v1.5.5
|
||||
"singleGossip", // Deprecated as of v1.5.5
|
||||
"root", // Deprecated as of v1.5.5
|
||||
"max", // Deprecated as of v1.5.5
|
||||
])
|
||||
.value_name("COMMITMENT_LEVEL")
|
||||
.hide_possible_values(true)
|
||||
.global(true)
|
||||
.help("Return information at the selected commitment level [possible values: processed, confirmed, finalized]"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("verbose")
|
||||
.long("verbose")
|
||||
.short("v")
|
||||
.global(true)
|
||||
.help("Show additional information"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("no_address_labels")
|
||||
.long("no-address-labels")
|
||||
.global(true)
|
||||
.help("Do not use address labels in the output"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("output_format")
|
||||
.long("output")
|
||||
.value_name("FORMAT")
|
||||
.global(true)
|
||||
.takes_value(true)
|
||||
.possible_values(&["json", "json-compact"])
|
||||
.help("Return information in specified output format"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(SKIP_SEED_PHRASE_VALIDATION_ARG.name)
|
||||
.long(SKIP_SEED_PHRASE_VALIDATION_ARG.long)
|
||||
.global(true)
|
||||
.help(SKIP_SEED_PHRASE_VALIDATION_ARG.help),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("rpc_timeout")
|
||||
.long("rpc-timeout")
|
||||
.value_name("SECONDS")
|
||||
.takes_value(true)
|
||||
.default_value(DEFAULT_RPC_TIMEOUT_SECONDS)
|
||||
.global(true)
|
||||
.hidden(true)
|
||||
.help("Timeout value for RPC requests"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("confirm_transaction_initial_timeout")
|
||||
.long("confirm-timeout")
|
||||
.value_name("SECONDS")
|
||||
.takes_value(true)
|
||||
.default_value(DEFAULT_CONFIRM_TX_TIMEOUT_SECONDS)
|
||||
.global(true)
|
||||
.hidden(true)
|
||||
.help("Timeout value for initial transaction status"),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("config")
|
||||
.about("Solana command-line tool configuration settings")
|
||||
.aliases(&["get", "set"])
|
||||
.setting(AppSettings::SubcommandRequiredElseHelp)
|
||||
.subcommand(
|
||||
SubCommand::with_name("get")
|
||||
.about("Get current config settings")
|
||||
.arg(
|
||||
Arg::with_name("specific_setting")
|
||||
.index(1)
|
||||
.value_name("CONFIG_FIELD")
|
||||
.takes_value(true)
|
||||
.possible_values(&[
|
||||
"json_rpc_url",
|
||||
"websocket_url",
|
||||
"keypair",
|
||||
"commitment",
|
||||
])
|
||||
.help("Return a specific config setting"),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("set")
|
||||
.about("Set a config setting")
|
||||
.group(
|
||||
ArgGroup::with_name("config_settings")
|
||||
.args(&["json_rpc_url", "websocket_url", "keypair", "commitment"])
|
||||
.multiple(true)
|
||||
.required(true),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("import-address-labels")
|
||||
.about("Import a list of address labels")
|
||||
.arg(
|
||||
Arg::with_name("filename")
|
||||
.index(1)
|
||||
.value_name("FILENAME")
|
||||
.takes_value(true)
|
||||
.help("YAML file of address labels"),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("export-address-labels")
|
||||
.about("Export the current address labels")
|
||||
.arg(
|
||||
Arg::with_name("filename")
|
||||
.index(1)
|
||||
.value_name("FILENAME")
|
||||
.takes_value(true)
|
||||
.help("YAML file to receive the current address labels"),
|
||||
),
|
||||
),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
do_main(&matches).map_err(|err| DisplayError::new_as_boxed(err).into())
|
||||
}
|
||||
|
||||
fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> {
|
||||
if parse_settings(matches)? {
|
||||
if parse_settings(&matches)? {
|
||||
let mut wallet_manager = None;
|
||||
|
||||
let (mut config, signers) = parse_args(matches, &mut wallet_manager)?;
|
||||
let (mut config, signers) = parse_args(&matches, &mut wallet_manager)?;
|
||||
config.signers = signers.iter().map(|s| s.as_ref()).collect();
|
||||
let result = process_command(&config)?;
|
||||
println!("{}", result);
|
||||
|
@@ -527,10 +527,10 @@ pub fn process_new_nonce(
|
||||
) -> ProcessResult {
|
||||
check_unique_pubkeys(
|
||||
(&config.signers[0].pubkey(), "cli keypair".to_string()),
|
||||
(nonce_account, "nonce_account_pubkey".to_string()),
|
||||
(&nonce_account, "nonce_account_pubkey".to_string()),
|
||||
)?;
|
||||
|
||||
if let Err(err) = rpc_client.get_account(nonce_account) {
|
||||
if let Err(err) = rpc_client.get_account(&nonce_account) {
|
||||
return Err(CliError::BadParameter(format!(
|
||||
"Unable to advance nonce account {}. error: {}",
|
||||
nonce_account, err
|
||||
@@ -540,7 +540,7 @@ pub fn process_new_nonce(
|
||||
|
||||
let nonce_authority = config.signers[nonce_authority];
|
||||
let ixs = vec![advance_nonce_account(
|
||||
nonce_account,
|
||||
&nonce_account,
|
||||
&nonce_authority.pubkey(),
|
||||
)]
|
||||
.with_memo(memo);
|
||||
@@ -588,7 +588,7 @@ pub fn process_show_nonce_account(
|
||||
use_lamports_unit,
|
||||
..CliNonceAccount::default()
|
||||
};
|
||||
if let Some(data) = data {
|
||||
if let Some(ref data) = data {
|
||||
nonce_account.nonce = Some(data.blockhash.to_string());
|
||||
nonce_account.lamports_per_signature = Some(data.fee_calculator.lamports_per_signature);
|
||||
nonce_account.authority = Some(data.authority.to_string());
|
||||
@@ -651,7 +651,7 @@ pub fn process_withdraw_from_nonce_account(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{clap_app::get_clap_app, cli::parse_command};
|
||||
use crate::cli::{app, parse_command};
|
||||
use solana_sdk::{
|
||||
account::Account,
|
||||
account_utils::StateMut,
|
||||
@@ -671,7 +671,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_parse_command() {
|
||||
let test_commands = get_clap_app("test", "desc", "version");
|
||||
let test_commands = app("test", "desc", "version");
|
||||
let default_keypair = Keypair::new();
|
||||
let (default_keypair_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -92,7 +92,7 @@ where
|
||||
Ok((message, spend))
|
||||
} else {
|
||||
let from_balance = rpc_client
|
||||
.get_balance_with_commitment(from_pubkey, commitment)?
|
||||
.get_balance_with_commitment(&from_pubkey, commitment)?
|
||||
.value;
|
||||
let (message, SpendAndFee { spend, fee }) = resolve_spend_message(
|
||||
amount,
|
||||
|
1161
cli/src/stake.rs
1161
cli/src/stake.rs
File diff suppressed because it is too large
Load Diff
@@ -119,7 +119,7 @@ fn parse_validator_info(
|
||||
let key_list: ConfigKeys = deserialize(&account.data)?;
|
||||
if !key_list.keys.is_empty() {
|
||||
let (validator_pubkey, _) = key_list.keys[1];
|
||||
let validator_info_string: String = deserialize(get_config_data(&account.data)?)?;
|
||||
let validator_info_string: String = deserialize(&get_config_data(&account.data)?)?;
|
||||
let validator_info: Map<_, _> = serde_json::from_str(&validator_info_string)?;
|
||||
Ok((validator_pubkey, validator_info))
|
||||
} else {
|
||||
@@ -246,7 +246,7 @@ pub fn process_set_validator_info(
|
||||
) -> ProcessResult {
|
||||
// Validate keybase username
|
||||
if let Some(string) = validator_info.get("keybaseUsername") {
|
||||
let result = verify_keybase(&config.signers[0].pubkey(), string);
|
||||
let result = verify_keybase(&config.signers[0].pubkey(), &string);
|
||||
if result.is_err() {
|
||||
if force_keybase {
|
||||
println!("--force supplied, ignoring: {:?}", result);
|
||||
@@ -272,7 +272,7 @@ pub fn process_set_validator_info(
|
||||
},
|
||||
)
|
||||
.find(|(pubkey, account)| {
|
||||
let (validator_pubkey, _) = parse_validator_info(pubkey, account).unwrap();
|
||||
let (validator_pubkey, _) = parse_validator_info(&pubkey, &account).unwrap();
|
||||
validator_pubkey == config.signers[0].pubkey()
|
||||
});
|
||||
|
||||
@@ -393,7 +393,7 @@ pub fn process_get_validator_info(
|
||||
}
|
||||
for (validator_info_pubkey, validator_info_account) in validator_info.iter() {
|
||||
let (validator_pubkey, validator_info) =
|
||||
parse_validator_info(validator_info_pubkey, validator_info_account)?;
|
||||
parse_validator_info(&validator_info_pubkey, &validator_info_account)?;
|
||||
validator_info_list.push(CliValidatorInfo {
|
||||
identity_pubkey: validator_pubkey.to_string(),
|
||||
info_pubkey: validator_info_pubkey.to_string(),
|
||||
@@ -408,7 +408,7 @@ pub fn process_get_validator_info(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::clap_app::get_clap_app;
|
||||
use crate::cli::app;
|
||||
use bincode::{serialize, serialized_size};
|
||||
use serde_json::json;
|
||||
|
||||
@@ -432,7 +432,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_parse_args() {
|
||||
let matches = get_clap_app("test", "desc", "version").get_matches_from(vec![
|
||||
let matches = app("test", "desc", "version").get_matches_from(vec![
|
||||
"test",
|
||||
"validator-info",
|
||||
"publish",
|
||||
@@ -451,7 +451,7 @@ mod tests {
|
||||
"name": "Alice",
|
||||
"keybaseUsername": "alice_keybase",
|
||||
});
|
||||
assert_eq!(parse_args(matches), expected);
|
||||
assert_eq!(parse_args(&matches), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
289
cli/src/vote.rs
289
cli/src/vote.rs
@@ -6,7 +6,6 @@ use crate::{
|
||||
},
|
||||
memo::WithMemo,
|
||||
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
|
||||
stake::check_current_authority,
|
||||
};
|
||||
use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand};
|
||||
use solana_clap_utils::{
|
||||
@@ -56,15 +55,6 @@ impl VoteSubCommands for App<'_, '_> {
|
||||
.validator(is_valid_signer)
|
||||
.help("Keypair of validator that will vote with this account"),
|
||||
)
|
||||
.arg(
|
||||
pubkey!(Arg::with_name("authorized_withdrawer")
|
||||
.index(3)
|
||||
.value_name("WITHDRAWER_PUBKEY")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.long("authorized-withdrawer"),
|
||||
"Public key of the authorized withdrawer")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("commission")
|
||||
.long("commission")
|
||||
@@ -80,12 +70,10 @@ impl VoteSubCommands for App<'_, '_> {
|
||||
"Public key of the authorized voter [default: validator identity pubkey]. "),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("allow_unsafe_authorized_withdrawer")
|
||||
.long("allow-unsafe-authorized-withdrawer")
|
||||
.takes_value(false)
|
||||
.help("Allow an authorized withdrawer pubkey to be identical to the validator identity \
|
||||
account pubkey or vote account pubkey, which is normally an unsafe \
|
||||
configuration and should be avoided."),
|
||||
pubkey!(Arg::with_name("authorized_withdrawer")
|
||||
.long("authorized-withdrawer")
|
||||
.value_name("WITHDRAWER_PUBKEY"),
|
||||
"Public key of the authorized withdrawer [default: validator identity pubkey]. "),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("seed")
|
||||
@@ -150,64 +138,6 @@ impl VoteSubCommands for App<'_, '_> {
|
||||
)
|
||||
.arg(memo_arg())
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("vote-authorize-voter-checked")
|
||||
.about("Authorize a new vote signing keypair for the given vote account, \
|
||||
checking the new authority as a signer")
|
||||
.arg(
|
||||
pubkey!(Arg::with_name("vote_account_pubkey")
|
||||
.index(1)
|
||||
.value_name("VOTE_ACCOUNT_ADDRESS")
|
||||
.required(true),
|
||||
"Vote account in which to set the authorized voter. "),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("authorized")
|
||||
.index(2)
|
||||
.value_name("AUTHORIZED_KEYPAIR")
|
||||
.required(true)
|
||||
.validator(is_valid_signer)
|
||||
.help("Current authorized vote signer."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("new_authorized")
|
||||
.index(3)
|
||||
.value_name("NEW_AUTHORIZED_KEYPAIR")
|
||||
.required(true)
|
||||
.validator(is_valid_signer)
|
||||
.help("New authorized vote signer."),
|
||||
)
|
||||
.arg(memo_arg())
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("vote-authorize-withdrawer-checked")
|
||||
.about("Authorize a new withdraw signing keypair for the given vote account, \
|
||||
checking the new authority as a signer")
|
||||
.arg(
|
||||
pubkey!(Arg::with_name("vote_account_pubkey")
|
||||
.index(1)
|
||||
.value_name("VOTE_ACCOUNT_ADDRESS")
|
||||
.required(true),
|
||||
"Vote account in which to set the authorized withdrawer. "),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("authorized")
|
||||
.index(2)
|
||||
.value_name("AUTHORIZED_KEYPAIR")
|
||||
.required(true)
|
||||
.validator(is_valid_signer)
|
||||
.help("Current authorized withdrawer."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("new_authorized")
|
||||
.index(3)
|
||||
.value_name("NEW_AUTHORIZED_KEYPAIR")
|
||||
.required(true)
|
||||
.validator(is_valid_signer)
|
||||
.help("New authorized withdrawer."),
|
||||
)
|
||||
.arg(memo_arg())
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("vote-update-validator")
|
||||
.about("Update the vote account's validator identity")
|
||||
@@ -352,28 +282,9 @@ pub fn parse_create_vote_account(
|
||||
signer_of(matches, "identity_account", wallet_manager)?;
|
||||
let commission = value_t_or_exit!(matches, "commission", u8);
|
||||
let authorized_voter = pubkey_of_signer(matches, "authorized_voter", wallet_manager)?;
|
||||
let authorized_withdrawer =
|
||||
pubkey_of_signer(matches, "authorized_withdrawer", wallet_manager)?.unwrap();
|
||||
let allow_unsafe = matches.is_present("allow_unsafe_authorized_withdrawer");
|
||||
let authorized_withdrawer = pubkey_of_signer(matches, "authorized_withdrawer", wallet_manager)?;
|
||||
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
|
||||
|
||||
if !allow_unsafe {
|
||||
if authorized_withdrawer == vote_account_pubkey.unwrap() {
|
||||
return Err(CliError::BadParameter(
|
||||
"Authorized withdrawer pubkey is identical to vote \
|
||||
account pubkey, an unsafe configuration"
|
||||
.to_owned(),
|
||||
));
|
||||
}
|
||||
if authorized_withdrawer == identity_pubkey.unwrap() {
|
||||
return Err(CliError::BadParameter(
|
||||
"Authorized withdrawer pubkey is identical to identity \
|
||||
account pubkey, an unsafe configuration"
|
||||
.to_owned(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let payer_provided = None;
|
||||
let signer_info = default_signer.generate_unique_signers(
|
||||
vec![payer_provided, vote_account, identity_account],
|
||||
@@ -400,25 +311,19 @@ pub fn parse_vote_authorize(
|
||||
default_signer: &DefaultSigner,
|
||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||
vote_authorize: VoteAuthorize,
|
||||
checked: bool,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let vote_account_pubkey =
|
||||
pubkey_of_signer(matches, "vote_account_pubkey", wallet_manager)?.unwrap();
|
||||
let (authorized, authorized_pubkey) = signer_of(matches, "authorized", wallet_manager)?;
|
||||
let new_authorized_pubkey =
|
||||
pubkey_of_signer(matches, "new_authorized_pubkey", wallet_manager)?.unwrap();
|
||||
let (authorized, _) = signer_of(matches, "authorized", wallet_manager)?;
|
||||
|
||||
let payer_provided = None;
|
||||
let mut signers = vec![payer_provided, authorized];
|
||||
|
||||
let new_authorized_pubkey = if checked {
|
||||
let (new_authorized_signer, new_authorized_pubkey) =
|
||||
signer_of(matches, "new_authorized", wallet_manager)?;
|
||||
signers.push(new_authorized_signer);
|
||||
new_authorized_pubkey.unwrap()
|
||||
} else {
|
||||
pubkey_of_signer(matches, "new_authorized_pubkey", wallet_manager)?.unwrap()
|
||||
};
|
||||
|
||||
let signer_info = default_signer.generate_unique_signers(signers, matches, wallet_manager)?;
|
||||
let signer_info = default_signer.generate_unique_signers(
|
||||
vec![payer_provided, authorized],
|
||||
matches,
|
||||
wallet_manager,
|
||||
)?;
|
||||
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
@@ -427,12 +332,6 @@ pub fn parse_vote_authorize(
|
||||
new_authorized_pubkey,
|
||||
vote_authorize,
|
||||
memo,
|
||||
authorized: signer_info.index_of(authorized_pubkey).unwrap(),
|
||||
new_authorized: if checked {
|
||||
signer_info.index_of(Some(new_authorized_pubkey))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
},
|
||||
signers: signer_info.signers,
|
||||
})
|
||||
@@ -562,14 +461,14 @@ pub fn process_create_vote_account(
|
||||
seed: &Option<String>,
|
||||
identity_account: SignerIndex,
|
||||
authorized_voter: &Option<Pubkey>,
|
||||
authorized_withdrawer: Pubkey,
|
||||
authorized_withdrawer: &Option<Pubkey>,
|
||||
commission: u8,
|
||||
memo: Option<&String>,
|
||||
) -> ProcessResult {
|
||||
let vote_account = config.signers[vote_account];
|
||||
let vote_account_pubkey = vote_account.pubkey();
|
||||
let vote_account_address = if let Some(seed) = seed {
|
||||
Pubkey::create_with_seed(&vote_account_pubkey, seed, &solana_vote_program::id())?
|
||||
Pubkey::create_with_seed(&vote_account_pubkey, &seed, &solana_vote_program::id())?
|
||||
} else {
|
||||
vote_account_pubkey
|
||||
};
|
||||
@@ -594,7 +493,7 @@ pub fn process_create_vote_account(
|
||||
let vote_init = VoteInit {
|
||||
node_pubkey: identity_pubkey,
|
||||
authorized_voter: authorized_voter.unwrap_or(identity_pubkey),
|
||||
authorized_withdrawer,
|
||||
authorized_withdrawer: authorized_withdrawer.unwrap_or(identity_pubkey),
|
||||
commission,
|
||||
};
|
||||
|
||||
@@ -650,7 +549,7 @@ pub fn process_create_vote_account(
|
||||
let mut tx = Transaction::new_unsigned(message);
|
||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<SystemError>(result, config)
|
||||
log_instruction_custom_error::<SystemError>(result, &config)
|
||||
}
|
||||
|
||||
pub fn process_vote_authorize(
|
||||
@@ -659,54 +558,28 @@ pub fn process_vote_authorize(
|
||||
vote_account_pubkey: &Pubkey,
|
||||
new_authorized_pubkey: &Pubkey,
|
||||
vote_authorize: VoteAuthorize,
|
||||
authorized: SignerIndex,
|
||||
new_authorized: Option<SignerIndex>,
|
||||
memo: Option<&String>,
|
||||
) -> ProcessResult {
|
||||
let authorized = config.signers[authorized];
|
||||
let new_authorized_signer = new_authorized.map(|index| config.signers[index]);
|
||||
// If the `authorized_account` is also the fee payer, `config.signers` will only have one
|
||||
// keypair in it
|
||||
let authorized = if config.signers.len() == 2 {
|
||||
config.signers[1]
|
||||
} else {
|
||||
config.signers[0]
|
||||
};
|
||||
|
||||
check_unique_pubkeys(
|
||||
(&authorized.pubkey(), "authorized_account".to_string()),
|
||||
(new_authorized_pubkey, "new_authorized_pubkey".to_string()),
|
||||
)?;
|
||||
|
||||
let (_, vote_state) = get_vote_account(rpc_client, vote_account_pubkey, config.commitment)?;
|
||||
match vote_authorize {
|
||||
VoteAuthorize::Voter => {
|
||||
let current_authorized_voter = vote_state
|
||||
.authorized_voters()
|
||||
.last()
|
||||
.ok_or_else(|| {
|
||||
CliError::RpcRequestError(
|
||||
"Invalid vote account state; no authorized voters found".to_string(),
|
||||
)
|
||||
})?
|
||||
.1;
|
||||
check_current_authority(current_authorized_voter, &authorized.pubkey())?
|
||||
}
|
||||
VoteAuthorize::Withdrawer => {
|
||||
check_current_authority(&vote_state.authorized_withdrawer, &authorized.pubkey())?
|
||||
}
|
||||
}
|
||||
|
||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
let vote_ix = if new_authorized_signer.is_some() {
|
||||
vote_instruction::authorize_checked(
|
||||
vote_account_pubkey, // vote account to update
|
||||
&authorized.pubkey(), // current authorized
|
||||
new_authorized_pubkey, // new vote signer/withdrawer
|
||||
vote_authorize, // vote or withdraw
|
||||
)
|
||||
} else {
|
||||
vote_instruction::authorize(
|
||||
vote_account_pubkey, // vote account to update
|
||||
&authorized.pubkey(), // current authorized
|
||||
new_authorized_pubkey, // new vote signer/withdrawer
|
||||
vote_authorize, // vote or withdraw
|
||||
)
|
||||
};
|
||||
let ixs = vec![vote_ix].with_memo(memo);
|
||||
let ixs = vec![vote_instruction::authorize(
|
||||
vote_account_pubkey, // vote account to update
|
||||
&authorized.pubkey(), // current authorized
|
||||
new_authorized_pubkey, // new vote signer/withdrawer
|
||||
vote_authorize, // vote or withdraw
|
||||
)]
|
||||
.with_memo(memo);
|
||||
|
||||
let message = Message::new(&ixs, Some(&config.signers[0].pubkey()));
|
||||
let mut tx = Transaction::new_unsigned(message);
|
||||
@@ -719,7 +592,7 @@ pub fn process_vote_authorize(
|
||||
config.commitment,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<VoteError>(result, config)
|
||||
log_instruction_custom_error::<VoteError>(result, &config)
|
||||
}
|
||||
|
||||
pub fn process_vote_update_validator(
|
||||
@@ -756,7 +629,7 @@ pub fn process_vote_update_validator(
|
||||
config.commitment,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<VoteError>(result, config)
|
||||
log_instruction_custom_error::<VoteError>(result, &config)
|
||||
}
|
||||
|
||||
pub fn process_vote_update_commission(
|
||||
@@ -787,7 +660,7 @@ pub fn process_vote_update_commission(
|
||||
config.commitment,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<VoteError>(result, config)
|
||||
log_instruction_custom_error::<VoteError>(result, &config)
|
||||
}
|
||||
|
||||
fn get_vote_account(
|
||||
@@ -890,7 +763,7 @@ pub fn process_withdraw_from_vote_account(
|
||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
let withdraw_authority = config.signers[withdraw_authority];
|
||||
|
||||
let current_balance = rpc_client.get_balance(vote_account_pubkey)?;
|
||||
let current_balance = rpc_client.get_balance(&vote_account_pubkey)?;
|
||||
let minimum_balance = rpc_client.get_minimum_balance_for_rent_exemption(VoteState::size_of())?;
|
||||
|
||||
let lamports = match withdraw_amount {
|
||||
@@ -925,13 +798,13 @@ pub fn process_withdraw_from_vote_account(
|
||||
config.commitment,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&transaction);
|
||||
log_instruction_custom_error::<VoteError>(result, config)
|
||||
log_instruction_custom_error::<VoteError>(result, &config)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{clap_app::get_clap_app, cli::parse_command};
|
||||
use crate::cli::{app, parse_command};
|
||||
use solana_sdk::signature::{read_keypair_file, write_keypair, Keypair, Signer};
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
@@ -942,7 +815,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_parse_command() {
|
||||
let test_commands = get_clap_app("test", "desc", "version");
|
||||
let test_commands = app("test", "desc", "version");
|
||||
let keypair = Keypair::new();
|
||||
let pubkey = keypair.pubkey();
|
||||
let pubkey_string = pubkey.to_string();
|
||||
@@ -970,8 +843,6 @@ mod tests {
|
||||
new_authorized_pubkey: pubkey2,
|
||||
vote_authorize: VoteAuthorize::Voter,
|
||||
memo: None,
|
||||
authorized: 0,
|
||||
new_authorized: None,
|
||||
},
|
||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
||||
}
|
||||
@@ -996,8 +867,6 @@ mod tests {
|
||||
new_authorized_pubkey: pubkey2,
|
||||
vote_authorize: VoteAuthorize::Voter,
|
||||
memo: None,
|
||||
authorized: 1,
|
||||
new_authorized: None,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
@@ -1006,84 +875,18 @@ mod tests {
|
||||
}
|
||||
);
|
||||
|
||||
let (voter_keypair_file, mut tmp_file) = make_tmp_file();
|
||||
let voter_keypair = Keypair::new();
|
||||
write_keypair(&voter_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
|
||||
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
"vote-authorize-voter-checked",
|
||||
&pubkey_string,
|
||||
&default_keypair_file,
|
||||
&voter_keypair_file,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_authorize_voter, &default_signer, &mut None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::VoteAuthorize {
|
||||
vote_account_pubkey: pubkey,
|
||||
new_authorized_pubkey: voter_keypair.pubkey(),
|
||||
vote_authorize: VoteAuthorize::Voter,
|
||||
memo: None,
|
||||
authorized: 0,
|
||||
new_authorized: Some(1),
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
read_keypair_file(&voter_keypair_file).unwrap().into()
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
"vote-authorize-voter-checked",
|
||||
&pubkey_string,
|
||||
&authorized_keypair_file,
|
||||
&voter_keypair_file,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_authorize_voter, &default_signer, &mut None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::VoteAuthorize {
|
||||
vote_account_pubkey: pubkey,
|
||||
new_authorized_pubkey: voter_keypair.pubkey(),
|
||||
vote_authorize: VoteAuthorize::Voter,
|
||||
memo: None,
|
||||
authorized: 1,
|
||||
new_authorized: Some(2),
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
read_keypair_file(&authorized_keypair_file).unwrap().into(),
|
||||
read_keypair_file(&voter_keypair_file).unwrap().into(),
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
"vote-authorize-voter-checked",
|
||||
&pubkey_string,
|
||||
&authorized_keypair_file,
|
||||
&pubkey2_string,
|
||||
]);
|
||||
assert!(parse_command(&test_authorize_voter, &default_signer, &mut None).is_err());
|
||||
|
||||
let (keypair_file, mut tmp_file) = make_tmp_file();
|
||||
let keypair = Keypair::new();
|
||||
write_keypair(&keypair, tmp_file.as_file_mut()).unwrap();
|
||||
// Test CreateVoteAccount SubCommand
|
||||
let (identity_keypair_file, mut tmp_file) = make_tmp_file();
|
||||
let identity_keypair = Keypair::new();
|
||||
let authorized_withdrawer = Keypair::new().pubkey();
|
||||
write_keypair(&identity_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
let test_create_vote_account = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
"create-vote-account",
|
||||
&keypair_file,
|
||||
&identity_keypair_file,
|
||||
&authorized_withdrawer.to_string(),
|
||||
"--commission",
|
||||
"10",
|
||||
]);
|
||||
@@ -1095,7 +898,7 @@ mod tests {
|
||||
seed: None,
|
||||
identity_account: 2,
|
||||
authorized_voter: None,
|
||||
authorized_withdrawer,
|
||||
authorized_withdrawer: None,
|
||||
commission: 10,
|
||||
memo: None,
|
||||
},
|
||||
@@ -1116,7 +919,6 @@ mod tests {
|
||||
"create-vote-account",
|
||||
&keypair_file,
|
||||
&identity_keypair_file,
|
||||
&authorized_withdrawer.to_string(),
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_create_vote_account2, &default_signer, &mut None).unwrap(),
|
||||
@@ -1126,7 +928,7 @@ mod tests {
|
||||
seed: None,
|
||||
identity_account: 2,
|
||||
authorized_voter: None,
|
||||
authorized_withdrawer,
|
||||
authorized_withdrawer: None,
|
||||
commission: 100,
|
||||
memo: None,
|
||||
},
|
||||
@@ -1149,7 +951,6 @@ mod tests {
|
||||
"create-vote-account",
|
||||
&keypair_file,
|
||||
&identity_keypair_file,
|
||||
&authorized_withdrawer.to_string(),
|
||||
"--authorized-voter",
|
||||
&authed.to_string(),
|
||||
]);
|
||||
@@ -1161,7 +962,7 @@ mod tests {
|
||||
seed: None,
|
||||
identity_account: 2,
|
||||
authorized_voter: Some(authed),
|
||||
authorized_withdrawer,
|
||||
authorized_withdrawer: None,
|
||||
commission: 100,
|
||||
memo: None,
|
||||
},
|
||||
@@ -1176,14 +977,14 @@ mod tests {
|
||||
let (keypair_file, mut tmp_file) = make_tmp_file();
|
||||
let keypair = Keypair::new();
|
||||
write_keypair(&keypair, tmp_file.as_file_mut()).unwrap();
|
||||
// succeed even though withdrawer unsafe (because forcefully allowed)
|
||||
// test init with an authed withdrawer
|
||||
let test_create_vote_account4 = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
"create-vote-account",
|
||||
&keypair_file,
|
||||
&identity_keypair_file,
|
||||
&identity_keypair_file,
|
||||
"--allow-unsafe-authorized-withdrawer",
|
||||
"--authorized-withdrawer",
|
||||
&authed.to_string(),
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_create_vote_account4, &default_signer, &mut None).unwrap(),
|
||||
@@ -1193,7 +994,7 @@ mod tests {
|
||||
seed: None,
|
||||
identity_account: 2,
|
||||
authorized_voter: None,
|
||||
authorized_withdrawer: identity_keypair.pubkey(),
|
||||
authorized_withdrawer: Some(authed),
|
||||
commission: 100,
|
||||
memo: None,
|
||||
},
|
||||
|
@@ -1,744 +0,0 @@
|
||||
use crate::{
|
||||
cli::{
|
||||
log_instruction_custom_error, request_and_confirm_airdrop, CliCommand, CliCommandInfo,
|
||||
CliConfig, CliError, ProcessResult,
|
||||
},
|
||||
memo::WithMemo,
|
||||
nonce::check_nonce_account,
|
||||
spend_utils::{resolve_spend_tx_and_check_account_balances, SpendAmount},
|
||||
};
|
||||
use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand};
|
||||
use solana_account_decoder::{UiAccount, UiAccountEncoding};
|
||||
use solana_clap_utils::{
|
||||
fee_payer::*,
|
||||
input_parsers::*,
|
||||
input_validators::*,
|
||||
keypair::{DefaultSigner, SignerIndex},
|
||||
memo::*,
|
||||
nonce::*,
|
||||
offline::*,
|
||||
};
|
||||
use solana_cli_output::{
|
||||
display::build_balance_message, return_signers_with_config, CliAccount,
|
||||
CliSignatureVerificationStatus, CliTransaction, CliTransactionConfirmation, OutputFormat,
|
||||
ReturnSignersConfig,
|
||||
};
|
||||
use solana_client::{
|
||||
blockhash_query::BlockhashQuery, nonce_utils, rpc_client::RpcClient,
|
||||
rpc_config::RpcTransactionConfig, rpc_response::RpcKeyedAccount,
|
||||
};
|
||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||
use solana_sdk::{
|
||||
commitment_config::CommitmentConfig,
|
||||
message::Message,
|
||||
pubkey::Pubkey,
|
||||
signature::Signature,
|
||||
stake,
|
||||
system_instruction::{self, SystemError},
|
||||
system_program,
|
||||
transaction::Transaction,
|
||||
};
|
||||
use solana_transaction_status::{EncodedTransaction, UiTransactionEncoding};
|
||||
use std::{fmt::Write as FmtWrite, fs::File, io::Write, sync::Arc};
|
||||
|
||||
pub trait WalletSubCommands {
|
||||
fn wallet_subcommands(self) -> Self;
|
||||
}
|
||||
|
||||
impl WalletSubCommands for App<'_, '_> {
|
||||
fn wallet_subcommands(self) -> Self {
|
||||
self.subcommand(
|
||||
SubCommand::with_name("account")
|
||||
.about("Show the contents of an account")
|
||||
.alias("account")
|
||||
.arg(
|
||||
pubkey!(Arg::with_name("account_pubkey")
|
||||
.index(1)
|
||||
.value_name("ACCOUNT_ADDRESS")
|
||||
.required(true),
|
||||
"Account key URI. ")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("output_file")
|
||||
.long("output-file")
|
||||
.short("o")
|
||||
.value_name("FILEPATH")
|
||||
.takes_value(true)
|
||||
.help("Write the account data to this file"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("lamports")
|
||||
.long("lamports")
|
||||
.takes_value(false)
|
||||
.help("Display balance in lamports instead of SOL"),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("address")
|
||||
.about("Get your public key")
|
||||
.arg(
|
||||
Arg::with_name("confirm_key")
|
||||
.long("confirm-key")
|
||||
.takes_value(false)
|
||||
.help("Confirm key on device; only relevant if using remote wallet"),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("airdrop")
|
||||
.about("Request SOL from a faucet")
|
||||
.arg(
|
||||
Arg::with_name("amount")
|
||||
.index(1)
|
||||
.value_name("AMOUNT")
|
||||
.takes_value(true)
|
||||
.validator(is_amount)
|
||||
.required(true)
|
||||
.help("The airdrop amount to request, in SOL"),
|
||||
)
|
||||
.arg(
|
||||
pubkey!(Arg::with_name("to")
|
||||
.index(2)
|
||||
.value_name("RECIPIENT_ADDRESS"),
|
||||
"The account address of airdrop recipient. "),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("balance")
|
||||
.about("Get your balance")
|
||||
.arg(
|
||||
pubkey!(Arg::with_name("pubkey")
|
||||
.index(1)
|
||||
.value_name("ACCOUNT_ADDRESS"),
|
||||
"The account address of the balance to check. ")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("lamports")
|
||||
.long("lamports")
|
||||
.takes_value(false)
|
||||
.help("Display balance in lamports instead of SOL"),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("confirm")
|
||||
.about("Confirm transaction by signature")
|
||||
.arg(
|
||||
Arg::with_name("signature")
|
||||
.index(1)
|
||||
.value_name("TRANSACTION_SIGNATURE")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.help("The transaction signature to confirm"),
|
||||
)
|
||||
.after_help(// Formatted specifically for the manually-indented heredoc string
|
||||
"Note: This will show more detailed information for finalized transactions with verbose mode (-v/--verbose).\
|
||||
\n\
|
||||
\nAccount modes:\
|
||||
\n |srwx|\
|
||||
\n s: signed\
|
||||
\n r: readable (always true)\
|
||||
\n w: writable\
|
||||
\n x: program account (inner instructions excluded)\
|
||||
"
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("create-address-with-seed")
|
||||
.about("Generate a derived account address with a seed")
|
||||
.arg(
|
||||
Arg::with_name("seed")
|
||||
.index(1)
|
||||
.value_name("SEED_STRING")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.validator(is_derived_address_seed)
|
||||
.help("The seed. Must not take more than 32 bytes to encode as utf-8"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("program_id")
|
||||
.index(2)
|
||||
.value_name("PROGRAM_ID")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.help(
|
||||
"The program_id that the address will ultimately be used for, \n\
|
||||
or one of NONCE, STAKE, and VOTE keywords",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
pubkey!(Arg::with_name("from")
|
||||
.long("from")
|
||||
.value_name("FROM_PUBKEY")
|
||||
.required(false),
|
||||
"From (base) key, [default: cli config keypair]. "),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("decode-transaction")
|
||||
.about("Decode a serialized transaction")
|
||||
.arg(
|
||||
Arg::with_name("transaction")
|
||||
.index(1)
|
||||
.value_name("TRANSACTION")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.help("transaction to decode"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("encoding")
|
||||
.index(2)
|
||||
.value_name("ENCODING")
|
||||
.possible_values(&["base58", "base64"]) // Subset of `UiTransactionEncoding` enum
|
||||
.default_value("base58")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.help("transaction encoding"),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("resolve-signer")
|
||||
.about("Checks that a signer is valid, and returns its specific path; useful for signers that may be specified generally, eg. usb://ledger")
|
||||
.arg(
|
||||
Arg::with_name("signer")
|
||||
.index(1)
|
||||
.value_name("SIGNER_KEYPAIR")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.validator(is_valid_signer)
|
||||
.help("The signer path to resolve")
|
||||
)
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("transfer")
|
||||
.about("Transfer funds between system accounts")
|
||||
.alias("pay")
|
||||
.arg(
|
||||
pubkey!(Arg::with_name("to")
|
||||
.index(1)
|
||||
.value_name("RECIPIENT_ADDRESS")
|
||||
.required(true),
|
||||
"The account address of recipient. "),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("amount")
|
||||
.index(2)
|
||||
.value_name("AMOUNT")
|
||||
.takes_value(true)
|
||||
.validator(is_amount_or_all)
|
||||
.required(true)
|
||||
.help("The amount to send, in SOL; accepts keyword ALL"),
|
||||
)
|
||||
.arg(
|
||||
pubkey!(Arg::with_name("from")
|
||||
.long("from")
|
||||
.value_name("FROM_ADDRESS"),
|
||||
"Source account of funds (if different from client local account). "),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("no_wait")
|
||||
.long("no-wait")
|
||||
.takes_value(false)
|
||||
.help("Return signature immediately after submitting the transaction, instead of waiting for confirmations"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("derived_address_seed")
|
||||
.long("derived-address-seed")
|
||||
.takes_value(true)
|
||||
.value_name("SEED_STRING")
|
||||
.requires("derived_address_program_id")
|
||||
.validator(is_derived_address_seed)
|
||||
.hidden(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("derived_address_program_id")
|
||||
.long("derived-address-program-id")
|
||||
.takes_value(true)
|
||||
.value_name("PROGRAM_ID")
|
||||
.requires("derived_address_seed")
|
||||
.hidden(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("allow_unfunded_recipient")
|
||||
.long("allow-unfunded-recipient")
|
||||
.takes_value(false)
|
||||
.help("Complete the transfer even if the recipient address is not funded")
|
||||
)
|
||||
.offline_args()
|
||||
.nonce_args(false)
|
||||
.arg(memo_arg())
|
||||
.arg(fee_payer_arg()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_derived_address_program_id(matches: &ArgMatches<'_>, arg_name: &str) -> Option<Pubkey> {
|
||||
matches.value_of(arg_name).and_then(|v| match v {
|
||||
"NONCE" => Some(system_program::id()),
|
||||
"STAKE" => Some(stake::program::id()),
|
||||
"VOTE" => Some(solana_vote_program::id()),
|
||||
_ => pubkey_of(matches, arg_name),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_account(
|
||||
matches: &ArgMatches<'_>,
|
||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let account_pubkey = pubkey_of_signer(matches, "account_pubkey", wallet_manager)?.unwrap();
|
||||
let output_file = matches.value_of("output_file");
|
||||
let use_lamports_unit = matches.is_present("lamports");
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::ShowAccount {
|
||||
pubkey: account_pubkey,
|
||||
output_file: output_file.map(ToString::to_string),
|
||||
use_lamports_unit,
|
||||
},
|
||||
signers: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_airdrop(
|
||||
matches: &ArgMatches<'_>,
|
||||
default_signer: &DefaultSigner,
|
||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let pubkey = pubkey_of_signer(matches, "to", wallet_manager)?;
|
||||
let signers = if pubkey.is_some() {
|
||||
vec![]
|
||||
} else {
|
||||
vec![default_signer.signer_from_path(matches, wallet_manager)?]
|
||||
};
|
||||
let lamports = lamports_of_sol(matches, "amount").unwrap();
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::Airdrop { pubkey, lamports },
|
||||
signers,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_balance(
|
||||
matches: &ArgMatches<'_>,
|
||||
default_signer: &DefaultSigner,
|
||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let pubkey = pubkey_of_signer(matches, "pubkey", wallet_manager)?;
|
||||
let signers = if pubkey.is_some() {
|
||||
vec![]
|
||||
} else {
|
||||
vec![default_signer.signer_from_path(matches, wallet_manager)?]
|
||||
};
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::Balance {
|
||||
pubkey,
|
||||
use_lamports_unit: matches.is_present("lamports"),
|
||||
},
|
||||
signers,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_decode_transaction(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||
let blob = value_t_or_exit!(matches, "transaction", String);
|
||||
let encoding = match matches.value_of("encoding").unwrap() {
|
||||
"base58" => UiTransactionEncoding::Base58,
|
||||
"base64" => UiTransactionEncoding::Base64,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let encoded_transaction = EncodedTransaction::Binary(blob, encoding);
|
||||
if let Some(transaction) = encoded_transaction.decode() {
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::DecodeTransaction(transaction),
|
||||
signers: vec![],
|
||||
})
|
||||
} else {
|
||||
Err(CliError::BadParameter(
|
||||
"Unable to decode transaction".to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_create_address_with_seed(
|
||||
matches: &ArgMatches<'_>,
|
||||
default_signer: &DefaultSigner,
|
||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let from_pubkey = pubkey_of_signer(matches, "from", wallet_manager)?;
|
||||
let signers = if from_pubkey.is_some() {
|
||||
vec![]
|
||||
} else {
|
||||
vec![default_signer.signer_from_path(matches, wallet_manager)?]
|
||||
};
|
||||
|
||||
let program_id = resolve_derived_address_program_id(matches, "program_id").unwrap();
|
||||
|
||||
let seed = matches.value_of("seed").unwrap().to_string();
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::CreateAddressWithSeed {
|
||||
from_pubkey,
|
||||
seed,
|
||||
program_id,
|
||||
},
|
||||
signers,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_transfer(
|
||||
matches: &ArgMatches<'_>,
|
||||
default_signer: &DefaultSigner,
|
||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let amount = SpendAmount::new_from_matches(matches, "amount");
|
||||
let to = pubkey_of_signer(matches, "to", wallet_manager)?.unwrap();
|
||||
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
||||
let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name);
|
||||
let no_wait = matches.is_present("no_wait");
|
||||
let blockhash_query = BlockhashQuery::new_from_matches(matches);
|
||||
let nonce_account = pubkey_of_signer(matches, NONCE_ARG.name, wallet_manager)?;
|
||||
let (nonce_authority, nonce_authority_pubkey) =
|
||||
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
|
||||
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
|
||||
let (fee_payer, fee_payer_pubkey) = signer_of(matches, FEE_PAYER_ARG.name, wallet_manager)?;
|
||||
let (from, from_pubkey) = signer_of(matches, "from", wallet_manager)?;
|
||||
let allow_unfunded_recipient = matches.is_present("allow_unfunded_recipient");
|
||||
|
||||
let mut bulk_signers = vec![fee_payer, from];
|
||||
if nonce_account.is_some() {
|
||||
bulk_signers.push(nonce_authority);
|
||||
}
|
||||
|
||||
let signer_info =
|
||||
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
|
||||
|
||||
let derived_address_seed = matches
|
||||
.value_of("derived_address_seed")
|
||||
.map(|s| s.to_string());
|
||||
let derived_address_program_id =
|
||||
resolve_derived_address_program_id(matches, "derived_address_program_id");
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::Transfer {
|
||||
amount,
|
||||
to,
|
||||
sign_only,
|
||||
dump_transaction_message,
|
||||
allow_unfunded_recipient,
|
||||
no_wait,
|
||||
blockhash_query,
|
||||
nonce_account,
|
||||
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
|
||||
memo,
|
||||
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
|
||||
from: signer_info.index_of(from_pubkey).unwrap(),
|
||||
derived_address_seed,
|
||||
derived_address_program_id,
|
||||
},
|
||||
signers: signer_info.signers,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn process_show_account(
|
||||
rpc_client: &RpcClient,
|
||||
config: &CliConfig,
|
||||
account_pubkey: &Pubkey,
|
||||
output_file: &Option<String>,
|
||||
use_lamports_unit: bool,
|
||||
) -> ProcessResult {
|
||||
let account = rpc_client.get_account(account_pubkey)?;
|
||||
let data = account.data.clone();
|
||||
let cli_account = CliAccount {
|
||||
keyed_account: RpcKeyedAccount {
|
||||
pubkey: account_pubkey.to_string(),
|
||||
account: UiAccount::encode(
|
||||
account_pubkey,
|
||||
&account,
|
||||
UiAccountEncoding::Base64,
|
||||
None,
|
||||
None,
|
||||
),
|
||||
},
|
||||
use_lamports_unit,
|
||||
};
|
||||
|
||||
let mut account_string = config.output_format.formatted_string(&cli_account);
|
||||
|
||||
if config.output_format == OutputFormat::Display
|
||||
|| config.output_format == OutputFormat::DisplayVerbose
|
||||
{
|
||||
if let Some(output_file) = output_file {
|
||||
let mut f = File::create(output_file)?;
|
||||
f.write_all(&data)?;
|
||||
writeln!(&mut account_string)?;
|
||||
writeln!(&mut account_string, "Wrote account data to {}", output_file)?;
|
||||
} else if !data.is_empty() {
|
||||
use pretty_hex::*;
|
||||
writeln!(&mut account_string, "{:?}", data.hex_dump())?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(account_string)
|
||||
}
|
||||
|
||||
pub fn process_airdrop(
|
||||
rpc_client: &RpcClient,
|
||||
config: &CliConfig,
|
||||
pubkey: &Option<Pubkey>,
|
||||
lamports: u64,
|
||||
) -> ProcessResult {
|
||||
let pubkey = if let Some(pubkey) = pubkey {
|
||||
*pubkey
|
||||
} else {
|
||||
config.pubkey()?
|
||||
};
|
||||
println!(
|
||||
"Requesting airdrop of {}",
|
||||
build_balance_message(lamports, false, true),
|
||||
);
|
||||
|
||||
let pre_balance = rpc_client.get_balance(&pubkey)?;
|
||||
|
||||
let result = request_and_confirm_airdrop(rpc_client, config, &pubkey, lamports);
|
||||
if let Ok(signature) = result {
|
||||
let signature_cli_message = log_instruction_custom_error::<SystemError>(result, config)?;
|
||||
println!("{}", signature_cli_message);
|
||||
|
||||
let current_balance = rpc_client.get_balance(&pubkey)?;
|
||||
|
||||
if current_balance < pre_balance.saturating_add(lamports) {
|
||||
println!("Balance unchanged");
|
||||
println!("Run `solana confirm -v {:?}` for more info", signature);
|
||||
Ok("".to_string())
|
||||
} else {
|
||||
Ok(build_balance_message(current_balance, false, true))
|
||||
}
|
||||
} else {
|
||||
log_instruction_custom_error::<SystemError>(result, config)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_balance(
|
||||
rpc_client: &RpcClient,
|
||||
config: &CliConfig,
|
||||
pubkey: &Option<Pubkey>,
|
||||
use_lamports_unit: bool,
|
||||
) -> ProcessResult {
|
||||
let pubkey = if let Some(pubkey) = pubkey {
|
||||
*pubkey
|
||||
} else {
|
||||
config.pubkey()?
|
||||
};
|
||||
let balance = rpc_client.get_balance(&pubkey)?;
|
||||
Ok(build_balance_message(balance, use_lamports_unit, true))
|
||||
}
|
||||
|
||||
pub fn process_confirm(
|
||||
rpc_client: &RpcClient,
|
||||
config: &CliConfig,
|
||||
signature: &Signature,
|
||||
) -> ProcessResult {
|
||||
match rpc_client.get_signature_statuses_with_history(&[*signature]) {
|
||||
Ok(status) => {
|
||||
let cli_transaction = if let Some(transaction_status) = &status.value[0] {
|
||||
let mut transaction = None;
|
||||
let mut get_transaction_error = None;
|
||||
if config.verbose {
|
||||
match rpc_client.get_transaction_with_config(
|
||||
signature,
|
||||
RpcTransactionConfig {
|
||||
encoding: Some(UiTransactionEncoding::Base64),
|
||||
commitment: Some(CommitmentConfig::confirmed()),
|
||||
},
|
||||
) {
|
||||
Ok(confirmed_transaction) => {
|
||||
let decoded_transaction = confirmed_transaction
|
||||
.transaction
|
||||
.transaction
|
||||
.decode()
|
||||
.expect("Successful decode");
|
||||
let json_transaction = EncodedTransaction::encode(
|
||||
decoded_transaction.clone(),
|
||||
UiTransactionEncoding::Json,
|
||||
);
|
||||
|
||||
transaction = Some(CliTransaction {
|
||||
transaction: json_transaction,
|
||||
meta: confirmed_transaction.transaction.meta,
|
||||
block_time: confirmed_transaction.block_time,
|
||||
slot: Some(confirmed_transaction.slot),
|
||||
decoded_transaction,
|
||||
prefix: " ".to_string(),
|
||||
sigverify_status: vec![],
|
||||
});
|
||||
}
|
||||
Err(err) => {
|
||||
get_transaction_error = Some(format!("{:?}", err));
|
||||
}
|
||||
}
|
||||
}
|
||||
CliTransactionConfirmation {
|
||||
confirmation_status: Some(transaction_status.confirmation_status()),
|
||||
transaction,
|
||||
get_transaction_error,
|
||||
err: transaction_status.err.clone(),
|
||||
}
|
||||
} else {
|
||||
CliTransactionConfirmation {
|
||||
confirmation_status: None,
|
||||
transaction: None,
|
||||
get_transaction_error: None,
|
||||
err: None,
|
||||
}
|
||||
};
|
||||
Ok(config.output_format.formatted_string(&cli_transaction))
|
||||
}
|
||||
Err(err) => Err(CliError::RpcRequestError(format!("Unable to confirm: {}", err)).into()),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::unnecessary_wraps)]
|
||||
pub fn process_decode_transaction(config: &CliConfig, transaction: &Transaction) -> ProcessResult {
|
||||
let sigverify_status = CliSignatureVerificationStatus::verify_transaction(transaction);
|
||||
let decode_transaction = CliTransaction {
|
||||
decoded_transaction: transaction.clone(),
|
||||
transaction: EncodedTransaction::encode(transaction.clone(), UiTransactionEncoding::Json),
|
||||
meta: None,
|
||||
block_time: None,
|
||||
slot: None,
|
||||
prefix: "".to_string(),
|
||||
sigverify_status,
|
||||
};
|
||||
Ok(config.output_format.formatted_string(&decode_transaction))
|
||||
}
|
||||
|
||||
pub fn process_create_address_with_seed(
|
||||
config: &CliConfig,
|
||||
from_pubkey: Option<&Pubkey>,
|
||||
seed: &str,
|
||||
program_id: &Pubkey,
|
||||
) -> ProcessResult {
|
||||
let from_pubkey = if let Some(pubkey) = from_pubkey {
|
||||
*pubkey
|
||||
} else {
|
||||
config.pubkey()?
|
||||
};
|
||||
let address = Pubkey::create_with_seed(&from_pubkey, seed, program_id)?;
|
||||
Ok(address.to_string())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn process_transfer(
|
||||
rpc_client: &RpcClient,
|
||||
config: &CliConfig,
|
||||
amount: SpendAmount,
|
||||
to: &Pubkey,
|
||||
from: SignerIndex,
|
||||
sign_only: bool,
|
||||
dump_transaction_message: bool,
|
||||
allow_unfunded_recipient: bool,
|
||||
no_wait: bool,
|
||||
blockhash_query: &BlockhashQuery,
|
||||
nonce_account: Option<&Pubkey>,
|
||||
nonce_authority: SignerIndex,
|
||||
memo: Option<&String>,
|
||||
fee_payer: SignerIndex,
|
||||
derived_address_seed: Option<String>,
|
||||
derived_address_program_id: Option<&Pubkey>,
|
||||
) -> ProcessResult {
|
||||
let from = config.signers[from];
|
||||
let mut from_pubkey = from.pubkey();
|
||||
|
||||
let (recent_blockhash, fee_calculator) =
|
||||
blockhash_query.get_blockhash_and_fee_calculator(rpc_client, config.commitment)?;
|
||||
|
||||
if !sign_only && !allow_unfunded_recipient {
|
||||
let recipient_balance = rpc_client
|
||||
.get_balance_with_commitment(to, config.commitment)?
|
||||
.value;
|
||||
if recipient_balance == 0 {
|
||||
return Err(format!(
|
||||
"The recipient address ({}) is not funded. \
|
||||
Add `--allow-unfunded-recipient` to complete the transfer \
|
||||
",
|
||||
to
|
||||
)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
|
||||
let nonce_authority = config.signers[nonce_authority];
|
||||
let fee_payer = config.signers[fee_payer];
|
||||
|
||||
let derived_parts = derived_address_seed.zip(derived_address_program_id);
|
||||
let with_seed = if let Some((seed, program_id)) = derived_parts {
|
||||
let base_pubkey = from_pubkey;
|
||||
from_pubkey = Pubkey::create_with_seed(&base_pubkey, &seed, program_id)?;
|
||||
Some((base_pubkey, seed, program_id, from_pubkey))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let build_message = |lamports| {
|
||||
let ixs = if let Some((base_pubkey, seed, program_id, from_pubkey)) = with_seed.as_ref() {
|
||||
vec![system_instruction::transfer_with_seed(
|
||||
from_pubkey,
|
||||
base_pubkey,
|
||||
seed.clone(),
|
||||
program_id,
|
||||
to,
|
||||
lamports,
|
||||
)]
|
||||
.with_memo(memo)
|
||||
} else {
|
||||
vec![system_instruction::transfer(&from_pubkey, to, lamports)].with_memo(memo)
|
||||
};
|
||||
|
||||
if let Some(nonce_account) = &nonce_account {
|
||||
Message::new_with_nonce(
|
||||
ixs,
|
||||
Some(&fee_payer.pubkey()),
|
||||
nonce_account,
|
||||
&nonce_authority.pubkey(),
|
||||
)
|
||||
} else {
|
||||
Message::new(&ixs, Some(&fee_payer.pubkey()))
|
||||
}
|
||||
};
|
||||
|
||||
let (message, _) = resolve_spend_tx_and_check_account_balances(
|
||||
rpc_client,
|
||||
sign_only,
|
||||
amount,
|
||||
&fee_calculator,
|
||||
&from_pubkey,
|
||||
&fee_payer.pubkey(),
|
||||
build_message,
|
||||
config.commitment,
|
||||
)?;
|
||||
let mut tx = Transaction::new_unsigned(message);
|
||||
|
||||
if sign_only {
|
||||
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
||||
return_signers_with_config(
|
||||
&tx,
|
||||
&config.output_format,
|
||||
&ReturnSignersConfig {
|
||||
dump_transaction_message,
|
||||
},
|
||||
)
|
||||
} else {
|
||||
if let Some(nonce_account) = &nonce_account {
|
||||
let nonce_account = nonce_utils::get_account_with_commitment(
|
||||
rpc_client,
|
||||
nonce_account,
|
||||
config.commitment,
|
||||
)?;
|
||||
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
|
||||
}
|
||||
|
||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||
let result = if no_wait {
|
||||
rpc_client.send_transaction(&tx)
|
||||
} else {
|
||||
rpc_client.send_and_confirm_transaction_with_spinner(&tx)
|
||||
};
|
||||
log_instruction_custom_error::<SystemError>(result, config)
|
||||
}
|
||||
}
|
@@ -18,15 +18,13 @@ use solana_sdk::{
|
||||
signature::{keypair_from_seed, Keypair, Signer},
|
||||
system_program,
|
||||
};
|
||||
use solana_streamer::socket::SocketAddrSpace;
|
||||
|
||||
#[test]
|
||||
fn test_nonce() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator =
|
||||
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
|
||||
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||
|
||||
full_battery_tests(test_validator, None, false);
|
||||
}
|
||||
@@ -36,8 +34,7 @@ fn test_nonce_with_seed() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator =
|
||||
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
|
||||
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||
|
||||
full_battery_tests(test_validator, Some(String::from("seed")), false);
|
||||
}
|
||||
@@ -47,8 +44,7 @@ fn test_nonce_with_authority() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator =
|
||||
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
|
||||
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||
|
||||
full_battery_tests(test_validator, None, true);
|
||||
}
|
||||
@@ -220,12 +216,7 @@ fn test_create_account_with_seed() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator = TestValidator::with_custom_fees(
|
||||
mint_pubkey,
|
||||
1,
|
||||
Some(faucet_addr),
|
||||
SocketAddrSpace::Unspecified,
|
||||
);
|
||||
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
|
||||
|
||||
let offline_nonce_authority_signer = keypair_from_seed(&[1u8; 32]).unwrap();
|
||||
let online_nonce_creator_signer = keypair_from_seed(&[2u8; 32]).unwrap();
|
||||
|
@@ -15,7 +15,6 @@ use solana_sdk::{
|
||||
pubkey::Pubkey,
|
||||
signature::{Keypair, Signer},
|
||||
};
|
||||
use solana_streamer::socket::SocketAddrSpace;
|
||||
use std::{env, fs::File, io::Read, path::PathBuf, str::FromStr};
|
||||
|
||||
#[test]
|
||||
@@ -31,8 +30,7 @@ fn test_cli_program_deploy_non_upgradeable() {
|
||||
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 test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -70,11 +68,11 @@ fn test_cli_program_deploy_non_upgradeable() {
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
let program_id = Pubkey::from_str(program_id_str).unwrap();
|
||||
let program_id = Pubkey::from_str(&program_id_str).unwrap();
|
||||
let account0 = rpc_client.get_account(&program_id).unwrap();
|
||||
assert_eq!(account0.lamports, minimum_balance_for_rent_exemption);
|
||||
assert_eq!(account0.owner, bpf_loader::id());
|
||||
assert!(account0.executable);
|
||||
assert_eq!(account0.executable, true);
|
||||
let mut file = File::open(pathbuf.to_str().unwrap().to_string()).unwrap();
|
||||
let mut elf = Vec::new();
|
||||
file.read_to_end(&mut elf).unwrap();
|
||||
@@ -95,7 +93,7 @@ fn test_cli_program_deploy_non_upgradeable() {
|
||||
.unwrap();
|
||||
assert_eq!(account1.lamports, minimum_balance_for_rent_exemption);
|
||||
assert_eq!(account1.owner, bpf_loader::id());
|
||||
assert!(account1.executable);
|
||||
assert_eq!(account1.executable, true);
|
||||
assert_eq!(account1.data, account0.data);
|
||||
|
||||
// Attempt to redeploy to the same address
|
||||
@@ -131,7 +129,7 @@ fn test_cli_program_deploy_non_upgradeable() {
|
||||
.unwrap();
|
||||
assert_eq!(account2.lamports, 2 * minimum_balance_for_rent_exemption);
|
||||
assert_eq!(account2.owner, bpf_loader::id());
|
||||
assert!(account2.executable);
|
||||
assert_eq!(account2.executable, true);
|
||||
assert_eq!(account2.data, account0.data);
|
||||
}
|
||||
|
||||
@@ -148,8 +146,7 @@ fn test_cli_program_deploy_no_authority() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator =
|
||||
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
|
||||
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -201,7 +198,7 @@ fn test_cli_program_deploy_no_authority() {
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
let program_id = Pubkey::from_str(program_id_str).unwrap();
|
||||
let program_id = Pubkey::from_str(&program_id_str).unwrap();
|
||||
|
||||
// Attempt to upgrade the program
|
||||
config.signers = vec![&keypair, &upgrade_authority];
|
||||
@@ -232,8 +229,7 @@ fn test_cli_program_deploy_with_authority() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator =
|
||||
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
|
||||
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -288,12 +284,12 @@ fn test_cli_program_deploy_with_authority() {
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
program_keypair.pubkey(),
|
||||
Pubkey::from_str(program_pubkey_str).unwrap()
|
||||
Pubkey::from_str(&program_pubkey_str).unwrap()
|
||||
);
|
||||
let program_account = rpc_client.get_account(&program_keypair.pubkey()).unwrap();
|
||||
assert_eq!(program_account.lamports, minimum_balance_for_program);
|
||||
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
|
||||
assert!(program_account.executable);
|
||||
assert_eq!(program_account.executable, true);
|
||||
let (programdata_pubkey, _) = Pubkey::find_program_address(
|
||||
&[program_keypair.pubkey().as_ref()],
|
||||
&bpf_loader_upgradeable::id(),
|
||||
@@ -304,7 +300,7 @@ fn test_cli_program_deploy_with_authority() {
|
||||
minimum_balance_for_programdata
|
||||
);
|
||||
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
|
||||
assert!(!programdata_account.executable);
|
||||
assert_eq!(programdata_account.executable, false);
|
||||
assert_eq!(
|
||||
programdata_account.data[UpgradeableLoaderState::programdata_data_offset().unwrap()..],
|
||||
program_data[..]
|
||||
@@ -332,11 +328,11 @@ fn test_cli_program_deploy_with_authority() {
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
let program_pubkey = Pubkey::from_str(program_pubkey_str).unwrap();
|
||||
let program_pubkey = Pubkey::from_str(&program_pubkey_str).unwrap();
|
||||
let program_account = rpc_client.get_account(&program_pubkey).unwrap();
|
||||
assert_eq!(program_account.lamports, minimum_balance_for_program);
|
||||
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
|
||||
assert!(program_account.executable);
|
||||
assert_eq!(program_account.executable, true);
|
||||
let (programdata_pubkey, _) =
|
||||
Pubkey::find_program_address(&[program_pubkey.as_ref()], &bpf_loader_upgradeable::id());
|
||||
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
|
||||
@@ -345,7 +341,7 @@ fn test_cli_program_deploy_with_authority() {
|
||||
minimum_balance_for_programdata
|
||||
);
|
||||
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
|
||||
assert!(!programdata_account.executable);
|
||||
assert_eq!(programdata_account.executable, false);
|
||||
assert_eq!(
|
||||
programdata_account.data[UpgradeableLoaderState::programdata_data_offset().unwrap()..],
|
||||
program_data[..]
|
||||
@@ -368,7 +364,7 @@ fn test_cli_program_deploy_with_authority() {
|
||||
let program_account = rpc_client.get_account(&program_pubkey).unwrap();
|
||||
assert_eq!(program_account.lamports, minimum_balance_for_program);
|
||||
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
|
||||
assert!(program_account.executable);
|
||||
assert_eq!(program_account.executable, true);
|
||||
let (programdata_pubkey, _) =
|
||||
Pubkey::find_program_address(&[program_pubkey.as_ref()], &bpf_loader_upgradeable::id());
|
||||
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
|
||||
@@ -377,7 +373,7 @@ fn test_cli_program_deploy_with_authority() {
|
||||
minimum_balance_for_programdata
|
||||
);
|
||||
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
|
||||
assert!(!programdata_account.executable);
|
||||
assert_eq!(programdata_account.executable, false);
|
||||
assert_eq!(
|
||||
programdata_account.data[UpgradeableLoaderState::programdata_data_offset().unwrap()..],
|
||||
program_data[..]
|
||||
@@ -401,7 +397,7 @@ fn test_cli_program_deploy_with_authority() {
|
||||
.as_str()
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
Pubkey::from_str(new_upgrade_authority_str).unwrap(),
|
||||
Pubkey::from_str(&new_upgrade_authority_str).unwrap(),
|
||||
new_upgrade_authority.pubkey()
|
||||
);
|
||||
|
||||
@@ -422,7 +418,7 @@ fn test_cli_program_deploy_with_authority() {
|
||||
let program_account = rpc_client.get_account(&program_pubkey).unwrap();
|
||||
assert_eq!(program_account.lamports, minimum_balance_for_program);
|
||||
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
|
||||
assert!(program_account.executable);
|
||||
assert_eq!(program_account.executable, true);
|
||||
let (programdata_pubkey, _) =
|
||||
Pubkey::find_program_address(&[program_pubkey.as_ref()], &bpf_loader_upgradeable::id());
|
||||
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
|
||||
@@ -431,7 +427,7 @@ fn test_cli_program_deploy_with_authority() {
|
||||
minimum_balance_for_programdata
|
||||
);
|
||||
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
|
||||
assert!(!programdata_account.executable);
|
||||
assert_eq!(programdata_account.executable, false);
|
||||
assert_eq!(
|
||||
programdata_account.data[UpgradeableLoaderState::programdata_data_offset().unwrap()..],
|
||||
program_data[..]
|
||||
@@ -442,8 +438,6 @@ fn test_cli_program_deploy_with_authority() {
|
||||
config.command = CliCommand::Program(ProgramCliCommand::Show {
|
||||
account_pubkey: Some(program_pubkey),
|
||||
authority_pubkey: keypair.pubkey(),
|
||||
get_programs: false,
|
||||
get_buffers: false,
|
||||
all: false,
|
||||
use_lamports_unit: false,
|
||||
});
|
||||
@@ -458,7 +452,7 @@ fn test_cli_program_deploy_with_authority() {
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
new_upgrade_authority.pubkey(),
|
||||
Pubkey::from_str(authority_pubkey_str).unwrap()
|
||||
Pubkey::from_str(&authority_pubkey_str).unwrap()
|
||||
);
|
||||
|
||||
// Set no authority
|
||||
@@ -516,7 +510,7 @@ fn test_cli_program_deploy_with_authority() {
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
let program_pubkey = Pubkey::from_str(program_pubkey_str).unwrap();
|
||||
let program_pubkey = Pubkey::from_str(&program_pubkey_str).unwrap();
|
||||
let (programdata_pubkey, _) =
|
||||
Pubkey::find_program_address(&[program_pubkey.as_ref()], &bpf_loader_upgradeable::id());
|
||||
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
|
||||
@@ -527,7 +521,7 @@ fn test_cli_program_deploy_with_authority() {
|
||||
{
|
||||
assert_eq!(upgrade_authority_address, None);
|
||||
} else {
|
||||
panic!("not a ProgramData account");
|
||||
panic!("not a buffer account");
|
||||
}
|
||||
|
||||
// Get buffer authority
|
||||
@@ -535,8 +529,6 @@ fn test_cli_program_deploy_with_authority() {
|
||||
config.command = CliCommand::Program(ProgramCliCommand::Show {
|
||||
account_pubkey: Some(program_pubkey),
|
||||
authority_pubkey: keypair.pubkey(),
|
||||
get_programs: false,
|
||||
get_buffers: false,
|
||||
all: false,
|
||||
use_lamports_unit: false,
|
||||
});
|
||||
@@ -552,88 +544,6 @@ fn test_cli_program_deploy_with_authority() {
|
||||
assert_eq!("none", authority_pubkey_str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cli_program_close_program() {
|
||||
solana_logger::setup();
|
||||
|
||||
let mut pathbuf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
pathbuf.push("tests");
|
||||
pathbuf.push("fixtures");
|
||||
pathbuf.push("noop");
|
||||
pathbuf.set_extension("so");
|
||||
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator =
|
||||
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
|
||||
let mut file = File::open(pathbuf.to_str().unwrap()).unwrap();
|
||||
let mut program_data = Vec::new();
|
||||
file.read_to_end(&mut program_data).unwrap();
|
||||
let max_len = program_data.len();
|
||||
let minimum_balance_for_programdata = rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(
|
||||
UpgradeableLoaderState::programdata_len(max_len).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let minimum_balance_for_program = rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(UpgradeableLoaderState::program_len().unwrap())
|
||||
.unwrap();
|
||||
let upgrade_authority = Keypair::new();
|
||||
|
||||
let mut config = CliConfig::recent_for_tests();
|
||||
let keypair = Keypair::new();
|
||||
config.json_rpc_url = test_validator.rpc_url();
|
||||
config.signers = vec![&keypair];
|
||||
config.command = CliCommand::Airdrop {
|
||||
pubkey: None,
|
||||
lamports: 100 * minimum_balance_for_programdata + minimum_balance_for_program,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
|
||||
// Deploy the upgradeable program
|
||||
let program_keypair = Keypair::new();
|
||||
config.signers = vec![&keypair, &upgrade_authority, &program_keypair];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
|
||||
program_location: Some(pathbuf.to_str().unwrap().to_string()),
|
||||
program_signer_index: Some(2),
|
||||
program_pubkey: Some(program_keypair.pubkey()),
|
||||
buffer_signer_index: None,
|
||||
buffer_pubkey: None,
|
||||
allow_excessive_balance: false,
|
||||
upgrade_authority_signer_index: 1,
|
||||
is_final: false,
|
||||
max_len: Some(max_len),
|
||||
});
|
||||
config.output_format = OutputFormat::JsonCompact;
|
||||
process_command(&config).unwrap();
|
||||
|
||||
let (programdata_pubkey, _) = Pubkey::find_program_address(
|
||||
&[program_keypair.pubkey().as_ref()],
|
||||
&bpf_loader_upgradeable::id(),
|
||||
);
|
||||
|
||||
// Close program
|
||||
let close_account = rpc_client.get_account(&programdata_pubkey).unwrap();
|
||||
let programdata_lamports = close_account.lamports;
|
||||
let recipient_pubkey = Pubkey::new_unique();
|
||||
config.signers = vec![&keypair, &upgrade_authority];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::Close {
|
||||
account_pubkey: Some(program_keypair.pubkey()),
|
||||
recipient_pubkey,
|
||||
authority_index: 1,
|
||||
use_lamports_unit: false,
|
||||
});
|
||||
process_command(&config).unwrap();
|
||||
rpc_client.get_account(&programdata_pubkey).unwrap_err();
|
||||
let recipient_account = rpc_client.get_account(&recipient_pubkey).unwrap();
|
||||
assert_eq!(programdata_lamports, recipient_account.lamports);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cli_program_write_buffer() {
|
||||
solana_logger::setup();
|
||||
@@ -647,8 +557,7 @@ fn test_cli_program_write_buffer() {
|
||||
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 test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -697,7 +606,7 @@ fn test_cli_program_write_buffer() {
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
let new_buffer_pubkey = Pubkey::from_str(buffer_pubkey_str).unwrap();
|
||||
let new_buffer_pubkey = Pubkey::from_str(&buffer_pubkey_str).unwrap();
|
||||
let buffer_account = rpc_client.get_account(&new_buffer_pubkey).unwrap();
|
||||
assert_eq!(buffer_account.lamports, minimum_balance_for_buffer_default);
|
||||
assert_eq!(buffer_account.owner, bpf_loader_upgradeable::id());
|
||||
@@ -732,7 +641,7 @@ fn test_cli_program_write_buffer() {
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
buffer_keypair.pubkey(),
|
||||
Pubkey::from_str(buffer_pubkey_str).unwrap()
|
||||
Pubkey::from_str(&buffer_pubkey_str).unwrap()
|
||||
);
|
||||
let buffer_account = rpc_client.get_account(&buffer_keypair.pubkey()).unwrap();
|
||||
assert_eq!(buffer_account.lamports, minimum_balance_for_buffer);
|
||||
@@ -752,8 +661,6 @@ fn test_cli_program_write_buffer() {
|
||||
config.command = CliCommand::Program(ProgramCliCommand::Show {
|
||||
account_pubkey: Some(buffer_keypair.pubkey()),
|
||||
authority_pubkey: keypair.pubkey(),
|
||||
get_programs: false,
|
||||
get_buffers: false,
|
||||
all: false,
|
||||
use_lamports_unit: false,
|
||||
});
|
||||
@@ -768,7 +675,7 @@ fn test_cli_program_write_buffer() {
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
keypair.pubkey(),
|
||||
Pubkey::from_str(authority_pubkey_str).unwrap()
|
||||
Pubkey::from_str(&authority_pubkey_str).unwrap()
|
||||
);
|
||||
|
||||
// Specify buffer authority
|
||||
@@ -793,7 +700,7 @@ fn test_cli_program_write_buffer() {
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
buffer_keypair.pubkey(),
|
||||
Pubkey::from_str(buffer_pubkey_str).unwrap()
|
||||
Pubkey::from_str(&buffer_pubkey_str).unwrap()
|
||||
);
|
||||
let buffer_account = rpc_client.get_account(&buffer_keypair.pubkey()).unwrap();
|
||||
assert_eq!(buffer_account.lamports, minimum_balance_for_buffer_default);
|
||||
@@ -828,7 +735,7 @@ fn test_cli_program_write_buffer() {
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
let buffer_pubkey = Pubkey::from_str(buffer_pubkey_str).unwrap();
|
||||
let buffer_pubkey = Pubkey::from_str(&buffer_pubkey_str).unwrap();
|
||||
let buffer_account = rpc_client.get_account(&buffer_pubkey).unwrap();
|
||||
assert_eq!(buffer_account.lamports, minimum_balance_for_buffer_default);
|
||||
assert_eq!(buffer_account.owner, bpf_loader_upgradeable::id());
|
||||
@@ -847,8 +754,6 @@ fn test_cli_program_write_buffer() {
|
||||
config.command = CliCommand::Program(ProgramCliCommand::Show {
|
||||
account_pubkey: Some(buffer_pubkey),
|
||||
authority_pubkey: keypair.pubkey(),
|
||||
get_programs: false,
|
||||
get_buffers: false,
|
||||
all: false,
|
||||
use_lamports_unit: false,
|
||||
});
|
||||
@@ -863,7 +768,7 @@ fn test_cli_program_write_buffer() {
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
authority_keypair.pubkey(),
|
||||
Pubkey::from_str(authority_pubkey_str).unwrap()
|
||||
Pubkey::from_str(&authority_pubkey_str).unwrap()
|
||||
);
|
||||
|
||||
// Close buffer
|
||||
@@ -901,7 +806,7 @@ fn test_cli_program_write_buffer() {
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
let new_buffer_pubkey = Pubkey::from_str(buffer_pubkey_str).unwrap();
|
||||
let new_buffer_pubkey = Pubkey::from_str(&buffer_pubkey_str).unwrap();
|
||||
|
||||
// Close buffers and deposit default keypair
|
||||
let pre_lamports = rpc_client.get_account(&keypair.pubkey()).unwrap().lamports;
|
||||
@@ -934,8 +839,7 @@ fn test_cli_program_set_buffer_authority() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator =
|
||||
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
|
||||
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -997,7 +901,7 @@ fn test_cli_program_set_buffer_authority() {
|
||||
.as_str()
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
Pubkey::from_str(new_buffer_authority_str).unwrap(),
|
||||
Pubkey::from_str(&new_buffer_authority_str).unwrap(),
|
||||
new_buffer_authority.pubkey()
|
||||
);
|
||||
let buffer_account = rpc_client.get_account(&buffer_keypair.pubkey()).unwrap();
|
||||
@@ -1024,7 +928,7 @@ fn test_cli_program_set_buffer_authority() {
|
||||
.as_str()
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
Pubkey::from_str(buffer_authority_str).unwrap(),
|
||||
Pubkey::from_str(&buffer_authority_str).unwrap(),
|
||||
buffer_keypair.pubkey()
|
||||
);
|
||||
let buffer_account = rpc_client.get_account(&buffer_keypair.pubkey()).unwrap();
|
||||
@@ -1048,8 +952,7 @@ fn test_cli_program_mismatch_buffer_authority() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator =
|
||||
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
|
||||
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -1138,8 +1041,7 @@ fn test_cli_program_show() {
|
||||
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 test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -1185,8 +1087,6 @@ fn test_cli_program_show() {
|
||||
config.command = CliCommand::Program(ProgramCliCommand::Show {
|
||||
account_pubkey: Some(buffer_keypair.pubkey()),
|
||||
authority_pubkey: keypair.pubkey(),
|
||||
get_programs: false,
|
||||
get_buffers: false,
|
||||
all: false,
|
||||
use_lamports_unit: false,
|
||||
});
|
||||
@@ -1201,7 +1101,7 @@ fn test_cli_program_show() {
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
buffer_keypair.pubkey(),
|
||||
Pubkey::from_str(address_str).unwrap()
|
||||
Pubkey::from_str(&address_str).unwrap()
|
||||
);
|
||||
let authority_str = json
|
||||
.as_object()
|
||||
@@ -1212,7 +1112,7 @@ fn test_cli_program_show() {
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
authority_keypair.pubkey(),
|
||||
Pubkey::from_str(authority_str).unwrap()
|
||||
Pubkey::from_str(&authority_str).unwrap()
|
||||
);
|
||||
let data_len = json
|
||||
.as_object()
|
||||
@@ -1247,8 +1147,6 @@ fn test_cli_program_show() {
|
||||
config.command = CliCommand::Program(ProgramCliCommand::Show {
|
||||
account_pubkey: Some(program_keypair.pubkey()),
|
||||
authority_pubkey: keypair.pubkey(),
|
||||
get_programs: false,
|
||||
get_buffers: false,
|
||||
all: false,
|
||||
use_lamports_unit: false,
|
||||
});
|
||||
@@ -1263,7 +1161,7 @@ fn test_cli_program_show() {
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
program_keypair.pubkey(),
|
||||
Pubkey::from_str(address_str).unwrap()
|
||||
Pubkey::from_str(&address_str).unwrap()
|
||||
);
|
||||
let programdata_address_str = json
|
||||
.as_object()
|
||||
@@ -1278,7 +1176,7 @@ fn test_cli_program_show() {
|
||||
);
|
||||
assert_eq!(
|
||||
programdata_pubkey,
|
||||
Pubkey::from_str(programdata_address_str).unwrap()
|
||||
Pubkey::from_str(&programdata_address_str).unwrap()
|
||||
);
|
||||
let authority_str = json
|
||||
.as_object()
|
||||
@@ -1289,7 +1187,7 @@ fn test_cli_program_show() {
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
authority_keypair.pubkey(),
|
||||
Pubkey::from_str(authority_str).unwrap()
|
||||
Pubkey::from_str(&authority_str).unwrap()
|
||||
);
|
||||
let deployed_slot = json
|
||||
.as_object()
|
||||
@@ -1323,8 +1221,7 @@ fn test_cli_program_dump() {
|
||||
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 test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
|
@@ -6,15 +6,13 @@ use solana_sdk::{
|
||||
commitment_config::CommitmentConfig,
|
||||
signature::{Keypair, Signer},
|
||||
};
|
||||
use solana_streamer::socket::SocketAddrSpace;
|
||||
|
||||
#[test]
|
||||
fn test_cli_request_airdrop() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator =
|
||||
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
|
||||
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||
|
||||
let mut bob_config = CliConfig::recent_for_tests();
|
||||
bob_config.json_rpc_url = test_validator.rpc_url();
|
||||
|
@@ -1,7 +1,6 @@
|
||||
use solana_cli::{
|
||||
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig},
|
||||
spend_utils::SpendAmount,
|
||||
stake::StakeAuthorizationIndexed,
|
||||
test_utils::{check_ready, check_recent_balance},
|
||||
};
|
||||
use solana_cli_output::{parse_sign_only_reply_string, OutputFormat};
|
||||
@@ -18,22 +17,18 @@ use solana_sdk::{
|
||||
nonce::State as NonceState,
|
||||
pubkey::Pubkey,
|
||||
signature::{keypair_from_seed, Keypair, Signer},
|
||||
stake::{
|
||||
self,
|
||||
instruction::LockupArgs,
|
||||
state::{Lockup, StakeAuthorize, StakeState},
|
||||
},
|
||||
};
|
||||
use solana_streamer::socket::SocketAddrSpace;
|
||||
use solana_stake_program::{
|
||||
stake_instruction::LockupArgs,
|
||||
stake_state::{Lockup, StakeAuthorize, StakeState},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_stake_delegation_force() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let authorized_withdrawer = Keypair::new().pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator =
|
||||
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
|
||||
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -54,7 +49,7 @@ fn test_stake_delegation_force() {
|
||||
seed: None,
|
||||
identity_account: 0,
|
||||
authorized_voter: None,
|
||||
authorized_withdrawer,
|
||||
authorized_withdrawer: None,
|
||||
commission: 0,
|
||||
memo: None,
|
||||
};
|
||||
@@ -68,7 +63,6 @@ fn test_stake_delegation_force() {
|
||||
seed: None,
|
||||
staker: None,
|
||||
withdrawer: None,
|
||||
withdrawer_signer: None,
|
||||
lockup: Lockup::default(),
|
||||
amount: SpendAmount::Some(50_000),
|
||||
sign_only: false,
|
||||
@@ -123,8 +117,7 @@ fn test_seed_stake_delegation_and_deactivation() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator =
|
||||
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
|
||||
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -146,7 +139,7 @@ fn test_seed_stake_delegation_and_deactivation() {
|
||||
let stake_address = Pubkey::create_with_seed(
|
||||
&config_validator.signers[0].pubkey(),
|
||||
"hi there",
|
||||
&stake::program::id(),
|
||||
&solana_stake_program::id(),
|
||||
)
|
||||
.expect("bad seed");
|
||||
|
||||
@@ -157,7 +150,6 @@ fn test_seed_stake_delegation_and_deactivation() {
|
||||
seed: Some("hi there".to_string()),
|
||||
staker: None,
|
||||
withdrawer: None,
|
||||
withdrawer_signer: None,
|
||||
lockup: Lockup::default(),
|
||||
amount: SpendAmount::Some(50_000),
|
||||
sign_only: false,
|
||||
@@ -210,8 +202,7 @@ fn test_stake_delegation_and_deactivation() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator =
|
||||
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
|
||||
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -239,7 +230,6 @@ fn test_stake_delegation_and_deactivation() {
|
||||
seed: None,
|
||||
staker: None,
|
||||
withdrawer: None,
|
||||
withdrawer_signer: None,
|
||||
lockup: Lockup::default(),
|
||||
amount: SpendAmount::Some(50_000),
|
||||
sign_only: false,
|
||||
@@ -293,8 +283,7 @@ fn test_offline_stake_delegation_and_deactivation() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator =
|
||||
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
|
||||
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -342,7 +331,6 @@ fn test_offline_stake_delegation_and_deactivation() {
|
||||
seed: None,
|
||||
staker: Some(config_offline.signers[0].pubkey()),
|
||||
withdrawer: None,
|
||||
withdrawer_signer: None,
|
||||
lockup: Lockup::default(),
|
||||
amount: SpendAmount::Some(50_000),
|
||||
sign_only: false,
|
||||
@@ -437,8 +425,7 @@ fn test_nonced_stake_delegation_and_deactivation() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator =
|
||||
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
|
||||
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -463,7 +450,6 @@ fn test_nonced_stake_delegation_and_deactivation() {
|
||||
seed: None,
|
||||
staker: None,
|
||||
withdrawer: None,
|
||||
withdrawer_signer: None,
|
||||
lockup: Lockup::default(),
|
||||
amount: SpendAmount::Some(50_000),
|
||||
sign_only: false,
|
||||
@@ -555,8 +541,7 @@ fn test_stake_authorize() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator =
|
||||
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
|
||||
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -595,7 +580,6 @@ fn test_stake_authorize() {
|
||||
seed: None,
|
||||
staker: None,
|
||||
withdrawer: None,
|
||||
withdrawer_signer: None,
|
||||
lockup: Lockup::default(),
|
||||
amount: SpendAmount::Some(50_000),
|
||||
sign_only: false,
|
||||
@@ -615,12 +599,7 @@ fn test_stake_authorize() {
|
||||
config.signers.pop();
|
||||
config.command = CliCommand::StakeAuthorize {
|
||||
stake_account_pubkey,
|
||||
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||
authorization_type: StakeAuthorize::Staker,
|
||||
new_authority_pubkey: online_authority_pubkey,
|
||||
authority: 0,
|
||||
new_authority_signer: None,
|
||||
}],
|
||||
new_authorizations: vec![(StakeAuthorize::Staker, online_authority_pubkey, 0)],
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
@@ -629,7 +608,6 @@ fn test_stake_authorize() {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
@@ -649,18 +627,8 @@ fn test_stake_authorize() {
|
||||
config.command = CliCommand::StakeAuthorize {
|
||||
stake_account_pubkey,
|
||||
new_authorizations: vec![
|
||||
StakeAuthorizationIndexed {
|
||||
authorization_type: StakeAuthorize::Staker,
|
||||
new_authority_pubkey: online_authority2_pubkey,
|
||||
authority: 1,
|
||||
new_authority_signer: None,
|
||||
},
|
||||
StakeAuthorizationIndexed {
|
||||
authorization_type: StakeAuthorize::Withdrawer,
|
||||
new_authority_pubkey: withdraw_authority_pubkey,
|
||||
authority: 0,
|
||||
new_authority_signer: None,
|
||||
},
|
||||
(StakeAuthorize::Staker, online_authority2_pubkey, 1),
|
||||
(StakeAuthorize::Withdrawer, withdraw_authority_pubkey, 0),
|
||||
],
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
@@ -670,7 +638,6 @@ fn test_stake_authorize() {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
@@ -687,12 +654,7 @@ fn test_stake_authorize() {
|
||||
config.signers.push(&online_authority2);
|
||||
config.command = CliCommand::StakeAuthorize {
|
||||
stake_account_pubkey,
|
||||
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||
authorization_type: StakeAuthorize::Staker,
|
||||
new_authority_pubkey: offline_authority_pubkey,
|
||||
authority: 1,
|
||||
new_authority_signer: None,
|
||||
}],
|
||||
new_authorizations: vec![(StakeAuthorize::Staker, offline_authority_pubkey, 1)],
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
@@ -701,7 +663,6 @@ fn test_stake_authorize() {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
@@ -718,12 +679,7 @@ fn test_stake_authorize() {
|
||||
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
|
||||
config_offline.command = CliCommand::StakeAuthorize {
|
||||
stake_account_pubkey,
|
||||
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||
authorization_type: StakeAuthorize::Staker,
|
||||
new_authority_pubkey: nonced_authority_pubkey,
|
||||
authority: 0,
|
||||
new_authority_signer: None,
|
||||
}],
|
||||
new_authorizations: vec![(StakeAuthorize::Staker, nonced_authority_pubkey, 0)],
|
||||
sign_only: true,
|
||||
dump_transaction_message: false,
|
||||
blockhash_query: BlockhashQuery::None(blockhash),
|
||||
@@ -732,7 +688,6 @@ fn test_stake_authorize() {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
config_offline.output_format = OutputFormat::JsonCompact;
|
||||
let sign_reply = process_command(&config_offline).unwrap();
|
||||
@@ -742,12 +697,7 @@ fn test_stake_authorize() {
|
||||
config.signers = vec![&offline_presigner];
|
||||
config.command = CliCommand::StakeAuthorize {
|
||||
stake_account_pubkey,
|
||||
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||
authorization_type: StakeAuthorize::Staker,
|
||||
new_authority_pubkey: nonced_authority_pubkey,
|
||||
authority: 0,
|
||||
new_authority_signer: None,
|
||||
}],
|
||||
new_authorizations: vec![(StakeAuthorize::Staker, nonced_authority_pubkey, 0)],
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
|
||||
@@ -756,7 +706,6 @@ fn test_stake_authorize() {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
@@ -798,12 +747,7 @@ fn test_stake_authorize() {
|
||||
config_offline.signers.push(&nonced_authority);
|
||||
config_offline.command = CliCommand::StakeAuthorize {
|
||||
stake_account_pubkey,
|
||||
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||
authorization_type: StakeAuthorize::Staker,
|
||||
new_authority_pubkey: online_authority_pubkey,
|
||||
authority: 1,
|
||||
new_authority_signer: None,
|
||||
}],
|
||||
new_authorizations: vec![(StakeAuthorize::Staker, online_authority_pubkey, 1)],
|
||||
sign_only: true,
|
||||
dump_transaction_message: false,
|
||||
blockhash_query: BlockhashQuery::None(nonce_hash),
|
||||
@@ -812,7 +756,6 @@ fn test_stake_authorize() {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
let sign_reply = process_command(&config_offline).unwrap();
|
||||
let sign_only = parse_sign_only_reply_string(&sign_reply);
|
||||
@@ -823,12 +766,7 @@ fn test_stake_authorize() {
|
||||
config.signers = vec![&offline_presigner, &nonced_authority_presigner];
|
||||
config.command = CliCommand::StakeAuthorize {
|
||||
stake_account_pubkey,
|
||||
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||
authorization_type: StakeAuthorize::Staker,
|
||||
new_authority_pubkey: online_authority_pubkey,
|
||||
authority: 1,
|
||||
new_authority_signer: None,
|
||||
}],
|
||||
new_authorizations: vec![(StakeAuthorize::Staker, online_authority_pubkey, 1)],
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(
|
||||
@@ -840,7 +778,6 @@ fn test_stake_authorize() {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
@@ -870,12 +807,7 @@ fn test_stake_authorize_with_fee_payer() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator = TestValidator::with_custom_fees(
|
||||
mint_pubkey,
|
||||
SIG_FEE,
|
||||
Some(faucet_addr),
|
||||
SocketAddrSpace::Unspecified,
|
||||
);
|
||||
let test_validator = TestValidator::with_custom_fees(mint_pubkey, SIG_FEE, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -921,7 +853,6 @@ fn test_stake_authorize_with_fee_payer() {
|
||||
seed: None,
|
||||
staker: None,
|
||||
withdrawer: None,
|
||||
withdrawer_signer: None,
|
||||
lockup: Lockup::default(),
|
||||
amount: SpendAmount::Some(50_000),
|
||||
sign_only: false,
|
||||
@@ -941,12 +872,7 @@ fn test_stake_authorize_with_fee_payer() {
|
||||
config.signers = vec![&default_signer, &payer_keypair];
|
||||
config.command = CliCommand::StakeAuthorize {
|
||||
stake_account_pubkey,
|
||||
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||
authorization_type: StakeAuthorize::Staker,
|
||||
new_authority_pubkey: offline_pubkey,
|
||||
authority: 0,
|
||||
new_authority_signer: None,
|
||||
}],
|
||||
new_authorizations: vec![(StakeAuthorize::Staker, offline_pubkey, 0)],
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
||||
@@ -955,7 +881,6 @@ fn test_stake_authorize_with_fee_payer() {
|
||||
memo: None,
|
||||
fee_payer: 1,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
// `config` balance has not changed, despite submitting the TX
|
||||
@@ -968,12 +893,7 @@ fn test_stake_authorize_with_fee_payer() {
|
||||
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
|
||||
config_offline.command = CliCommand::StakeAuthorize {
|
||||
stake_account_pubkey,
|
||||
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||
authorization_type: StakeAuthorize::Staker,
|
||||
new_authority_pubkey: payer_pubkey,
|
||||
authority: 0,
|
||||
new_authority_signer: None,
|
||||
}],
|
||||
new_authorizations: vec![(StakeAuthorize::Staker, payer_pubkey, 0)],
|
||||
sign_only: true,
|
||||
dump_transaction_message: false,
|
||||
blockhash_query: BlockhashQuery::None(blockhash),
|
||||
@@ -982,7 +902,6 @@ fn test_stake_authorize_with_fee_payer() {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
config_offline.output_format = OutputFormat::JsonCompact;
|
||||
let sign_reply = process_command(&config_offline).unwrap();
|
||||
@@ -992,12 +911,7 @@ fn test_stake_authorize_with_fee_payer() {
|
||||
config.signers = vec![&offline_presigner];
|
||||
config.command = CliCommand::StakeAuthorize {
|
||||
stake_account_pubkey,
|
||||
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||
authorization_type: StakeAuthorize::Staker,
|
||||
new_authority_pubkey: payer_pubkey,
|
||||
authority: 0,
|
||||
new_authority_signer: None,
|
||||
}],
|
||||
new_authorizations: vec![(StakeAuthorize::Staker, payer_pubkey, 0)],
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
|
||||
@@ -1006,7 +920,6 @@ fn test_stake_authorize_with_fee_payer() {
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
// `config`'s balance again has not changed
|
||||
@@ -1023,12 +936,7 @@ fn test_stake_split() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator = TestValidator::with_custom_fees(
|
||||
mint_pubkey,
|
||||
1,
|
||||
Some(faucet_addr),
|
||||
SocketAddrSpace::Unspecified,
|
||||
);
|
||||
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -1066,7 +974,6 @@ fn test_stake_split() {
|
||||
seed: None,
|
||||
staker: Some(offline_pubkey),
|
||||
withdrawer: Some(offline_pubkey),
|
||||
withdrawer_signer: None,
|
||||
lockup: Lockup::default(),
|
||||
amount: SpendAmount::Some(10 * minimum_stake_balance),
|
||||
sign_only: false,
|
||||
@@ -1172,12 +1079,7 @@ fn test_stake_set_lockup() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator = TestValidator::with_custom_fees(
|
||||
mint_pubkey,
|
||||
1,
|
||||
Some(faucet_addr),
|
||||
SocketAddrSpace::Unspecified,
|
||||
);
|
||||
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -1222,7 +1124,6 @@ fn test_stake_set_lockup() {
|
||||
seed: None,
|
||||
staker: Some(offline_pubkey),
|
||||
withdrawer: Some(config.signers[0].pubkey()),
|
||||
withdrawer_signer: None,
|
||||
lockup,
|
||||
amount: SpendAmount::Some(10 * minimum_stake_balance),
|
||||
sign_only: false,
|
||||
@@ -1251,7 +1152,6 @@ fn test_stake_set_lockup() {
|
||||
config.command = CliCommand::StakeSetLockup {
|
||||
stake_account_pubkey,
|
||||
lockup,
|
||||
new_custodian_signer: None,
|
||||
custodian: 0,
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
@@ -1287,7 +1187,6 @@ fn test_stake_set_lockup() {
|
||||
config.command = CliCommand::StakeSetLockup {
|
||||
stake_account_pubkey,
|
||||
lockup,
|
||||
new_custodian_signer: None,
|
||||
custodian: 0,
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
@@ -1308,7 +1207,6 @@ fn test_stake_set_lockup() {
|
||||
config.command = CliCommand::StakeSetLockup {
|
||||
stake_account_pubkey,
|
||||
lockup,
|
||||
new_custodian_signer: None,
|
||||
custodian: 1,
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
@@ -1341,7 +1239,6 @@ fn test_stake_set_lockup() {
|
||||
config.command = CliCommand::StakeSetLockup {
|
||||
stake_account_pubkey,
|
||||
lockup,
|
||||
new_custodian_signer: None,
|
||||
custodian: 1,
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
@@ -1389,7 +1286,6 @@ fn test_stake_set_lockup() {
|
||||
config_offline.command = CliCommand::StakeSetLockup {
|
||||
stake_account_pubkey,
|
||||
lockup,
|
||||
new_custodian_signer: None,
|
||||
custodian: 0,
|
||||
sign_only: true,
|
||||
dump_transaction_message: false,
|
||||
@@ -1408,7 +1304,6 @@ fn test_stake_set_lockup() {
|
||||
config.command = CliCommand::StakeSetLockup {
|
||||
stake_account_pubkey,
|
||||
lockup,
|
||||
new_custodian_signer: None,
|
||||
custodian: 0,
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
@@ -1443,8 +1338,7 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator =
|
||||
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
|
||||
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -1504,7 +1398,6 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
|
||||
seed: None,
|
||||
staker: None,
|
||||
withdrawer: None,
|
||||
withdrawer_signer: None,
|
||||
lockup: Lockup::default(),
|
||||
amount: SpendAmount::Some(50_000),
|
||||
sign_only: true,
|
||||
@@ -1528,7 +1421,6 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
|
||||
seed: None,
|
||||
staker: Some(offline_pubkey),
|
||||
withdrawer: None,
|
||||
withdrawer_signer: None,
|
||||
lockup: Lockup::default(),
|
||||
amount: SpendAmount::Some(50_000),
|
||||
sign_only: false,
|
||||
@@ -1618,7 +1510,6 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
|
||||
seed: Some(seed.to_string()),
|
||||
staker: None,
|
||||
withdrawer: None,
|
||||
withdrawer_signer: None,
|
||||
lockup: Lockup::default(),
|
||||
amount: SpendAmount::Some(50_000),
|
||||
sign_only: true,
|
||||
@@ -1640,7 +1531,6 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
|
||||
seed: Some(seed.to_string()),
|
||||
staker: Some(offline_pubkey),
|
||||
withdrawer: Some(offline_pubkey),
|
||||
withdrawer_signer: None,
|
||||
lockup: Lockup::default(),
|
||||
amount: SpendAmount::Some(50_000),
|
||||
sign_only: false,
|
||||
@@ -1657,232 +1547,6 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let seed_address =
|
||||
Pubkey::create_with_seed(&stake_pubkey, seed, &stake::program::id()).unwrap();
|
||||
Pubkey::create_with_seed(&stake_pubkey, seed, &solana_stake_program::id()).unwrap();
|
||||
check_recent_balance(50_000, &rpc_client, &seed_address);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stake_checked_instructions() {
|
||||
solana_logger::setup();
|
||||
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator =
|
||||
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
let default_signer = Keypair::new();
|
||||
|
||||
let mut config = CliConfig::recent_for_tests();
|
||||
config.json_rpc_url = test_validator.rpc_url();
|
||||
config.signers = vec![&default_signer];
|
||||
|
||||
request_and_confirm_airdrop(&rpc_client, &config, &config.signers[0].pubkey(), 100_000)
|
||||
.unwrap();
|
||||
|
||||
// Create stake account with withdrawer
|
||||
let stake_keypair = Keypair::new();
|
||||
let stake_account_pubkey = stake_keypair.pubkey();
|
||||
let withdrawer_keypair = Keypair::new();
|
||||
let withdrawer_pubkey = withdrawer_keypair.pubkey();
|
||||
config.signers.push(&stake_keypair);
|
||||
config.command = CliCommand::CreateStakeAccount {
|
||||
stake_account: 1,
|
||||
seed: None,
|
||||
staker: None,
|
||||
withdrawer: Some(withdrawer_pubkey),
|
||||
withdrawer_signer: Some(1),
|
||||
lockup: Lockup::default(),
|
||||
amount: SpendAmount::Some(50_000),
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
from: 0,
|
||||
};
|
||||
process_command(&config).unwrap_err(); // unsigned authority should fail
|
||||
|
||||
config.signers = vec![&default_signer, &stake_keypair, &withdrawer_keypair];
|
||||
config.command = CliCommand::CreateStakeAccount {
|
||||
stake_account: 1,
|
||||
seed: None,
|
||||
staker: None,
|
||||
withdrawer: Some(withdrawer_pubkey),
|
||||
withdrawer_signer: Some(1),
|
||||
lockup: Lockup::default(),
|
||||
amount: SpendAmount::Some(50_000),
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
from: 0,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
|
||||
// Re-authorize account, checking new authority
|
||||
let staker_keypair = Keypair::new();
|
||||
let staker_pubkey = staker_keypair.pubkey();
|
||||
config.signers = vec![&default_signer];
|
||||
config.command = CliCommand::StakeAuthorize {
|
||||
stake_account_pubkey,
|
||||
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||
authorization_type: StakeAuthorize::Staker,
|
||||
new_authority_pubkey: staker_pubkey,
|
||||
authority: 0,
|
||||
new_authority_signer: Some(0),
|
||||
}],
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
process_command(&config).unwrap_err(); // unsigned authority should fail
|
||||
|
||||
config.signers = vec![&default_signer, &staker_keypair];
|
||||
config.command = CliCommand::StakeAuthorize {
|
||||
stake_account_pubkey,
|
||||
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||
authorization_type: StakeAuthorize::Staker,
|
||||
new_authority_pubkey: staker_pubkey,
|
||||
authority: 0,
|
||||
new_authority_signer: Some(1),
|
||||
}],
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
let stake_state: StakeState = stake_account.state().unwrap();
|
||||
let current_authority = match stake_state {
|
||||
StakeState::Initialized(meta) => meta.authorized.staker,
|
||||
_ => panic!("Unexpected stake state!"),
|
||||
};
|
||||
assert_eq!(current_authority, staker_pubkey);
|
||||
|
||||
let new_withdrawer_keypair = Keypair::new();
|
||||
let new_withdrawer_pubkey = new_withdrawer_keypair.pubkey();
|
||||
config.signers = vec![&default_signer, &withdrawer_keypair];
|
||||
config.command = CliCommand::StakeAuthorize {
|
||||
stake_account_pubkey,
|
||||
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||
authorization_type: StakeAuthorize::Withdrawer,
|
||||
new_authority_pubkey: new_withdrawer_pubkey,
|
||||
authority: 1,
|
||||
new_authority_signer: Some(1),
|
||||
}],
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
process_command(&config).unwrap_err(); // unsigned authority should fail
|
||||
|
||||
config.signers = vec![
|
||||
&default_signer,
|
||||
&withdrawer_keypair,
|
||||
&new_withdrawer_keypair,
|
||||
];
|
||||
config.command = CliCommand::StakeAuthorize {
|
||||
stake_account_pubkey,
|
||||
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||
authorization_type: StakeAuthorize::Withdrawer,
|
||||
new_authority_pubkey: new_withdrawer_pubkey,
|
||||
authority: 1,
|
||||
new_authority_signer: Some(2),
|
||||
}],
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
no_wait: false,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
let stake_state: StakeState = stake_account.state().unwrap();
|
||||
let current_authority = match stake_state {
|
||||
StakeState::Initialized(meta) => meta.authorized.withdrawer,
|
||||
_ => panic!("Unexpected stake state!"),
|
||||
};
|
||||
assert_eq!(current_authority, new_withdrawer_pubkey);
|
||||
|
||||
// Set lockup, checking new custodian
|
||||
let custodian = Keypair::new();
|
||||
let custodian_pubkey = custodian.pubkey();
|
||||
let lockup = LockupArgs {
|
||||
unix_timestamp: Some(1_581_534_570),
|
||||
epoch: Some(200),
|
||||
custodian: Some(custodian_pubkey),
|
||||
};
|
||||
config.signers = vec![&default_signer, &new_withdrawer_keypair];
|
||||
config.command = CliCommand::StakeSetLockup {
|
||||
stake_account_pubkey,
|
||||
lockup,
|
||||
new_custodian_signer: Some(1),
|
||||
custodian: 1,
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
};
|
||||
process_command(&config).unwrap_err(); // unsigned new custodian should fail
|
||||
|
||||
config.signers = vec![&default_signer, &new_withdrawer_keypair, &custodian];
|
||||
config.command = CliCommand::StakeSetLockup {
|
||||
stake_account_pubkey,
|
||||
lockup,
|
||||
new_custodian_signer: Some(2),
|
||||
custodian: 1,
|
||||
sign_only: false,
|
||||
dump_transaction_message: false,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
memo: None,
|
||||
fee_payer: 0,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
let stake_state: StakeState = stake_account.state().unwrap();
|
||||
let current_lockup = match stake_state {
|
||||
StakeState::Initialized(meta) => meta.lockup,
|
||||
_ => panic!("Unexpected stake state!"),
|
||||
};
|
||||
assert_eq!(
|
||||
current_lockup.unix_timestamp,
|
||||
lockup.unix_timestamp.unwrap()
|
||||
);
|
||||
assert_eq!(current_lockup.epoch, lockup.epoch.unwrap());
|
||||
assert_eq!(current_lockup.custodian, custodian_pubkey);
|
||||
}
|
||||
|
@@ -16,9 +16,7 @@ use solana_sdk::{
|
||||
nonce::State as NonceState,
|
||||
pubkey::Pubkey,
|
||||
signature::{keypair_from_seed, Keypair, NullSigner, Signer},
|
||||
stake,
|
||||
};
|
||||
use solana_streamer::socket::SocketAddrSpace;
|
||||
|
||||
#[test]
|
||||
fn test_transfer() {
|
||||
@@ -26,12 +24,7 @@ fn test_transfer() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator = TestValidator::with_custom_fees(
|
||||
mint_pubkey,
|
||||
1,
|
||||
Some(faucet_addr),
|
||||
SocketAddrSpace::Unspecified,
|
||||
);
|
||||
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -283,12 +276,7 @@ fn test_transfer_multisession_signing() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator = TestValidator::with_custom_fees(
|
||||
mint_pubkey,
|
||||
1,
|
||||
Some(faucet_addr),
|
||||
SocketAddrSpace::Unspecified,
|
||||
);
|
||||
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
|
||||
|
||||
let to_pubkey = Pubkey::new(&[1u8; 32]);
|
||||
let offline_from_signer = keypair_from_seed(&[2u8; 32]).unwrap();
|
||||
@@ -415,12 +403,7 @@ fn test_transfer_all() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator = TestValidator::with_custom_fees(
|
||||
mint_pubkey,
|
||||
1,
|
||||
Some(faucet_addr),
|
||||
SocketAddrSpace::Unspecified,
|
||||
);
|
||||
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -468,12 +451,7 @@ fn test_transfer_unfunded_recipient() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator = TestValidator::with_custom_fees(
|
||||
mint_pubkey,
|
||||
1,
|
||||
Some(faucet_addr),
|
||||
SocketAddrSpace::Unspecified,
|
||||
);
|
||||
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -521,12 +499,7 @@ fn test_transfer_with_seed() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator = TestValidator::with_custom_fees(
|
||||
mint_pubkey,
|
||||
1,
|
||||
Some(faucet_addr),
|
||||
SocketAddrSpace::Unspecified,
|
||||
);
|
||||
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -540,7 +513,7 @@ fn test_transfer_with_seed() {
|
||||
let sender_pubkey = config.signers[0].pubkey();
|
||||
let recipient_pubkey = Pubkey::new(&[1u8; 32]);
|
||||
let derived_address_seed = "seed".to_string();
|
||||
let derived_address_program_id = stake::program::id();
|
||||
let derived_address_program_id = solana_stake_program::id();
|
||||
let derived_address = Pubkey::create_with_seed(
|
||||
&sender_pubkey,
|
||||
&derived_address_seed,
|
||||
|
@@ -14,7 +14,6 @@ use solana_sdk::{
|
||||
commitment_config::CommitmentConfig,
|
||||
signature::{Keypair, Signer},
|
||||
};
|
||||
use solana_streamer::socket::SocketAddrSpace;
|
||||
use solana_vote_program::vote_state::{VoteAuthorize, VoteState, VoteStateVersions};
|
||||
|
||||
#[test]
|
||||
@@ -22,8 +21,7 @@ fn test_vote_authorize_and_withdraw() {
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
let test_validator =
|
||||
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
|
||||
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||
@@ -45,7 +43,7 @@ fn test_vote_authorize_and_withdraw() {
|
||||
seed: None,
|
||||
identity_account: 0,
|
||||
authorized_voter: None,
|
||||
authorized_withdrawer: config.signers[0].pubkey(),
|
||||
authorized_withdrawer: Some(config.signers[0].pubkey()),
|
||||
commission: 0,
|
||||
memo: None,
|
||||
};
|
||||
@@ -85,48 +83,13 @@ fn test_vote_authorize_and_withdraw() {
|
||||
check_recent_balance(expected_balance, &rpc_client, &vote_account_pubkey);
|
||||
|
||||
// Authorize vote account withdrawal to another signer
|
||||
let first_withdraw_authority = Keypair::new();
|
||||
let withdraw_authority = Keypair::new();
|
||||
config.signers = vec![&default_signer];
|
||||
config.command = CliCommand::VoteAuthorize {
|
||||
vote_account_pubkey,
|
||||
new_authorized_pubkey: first_withdraw_authority.pubkey(),
|
||||
vote_authorize: VoteAuthorize::Withdrawer,
|
||||
memo: None,
|
||||
authorized: 0,
|
||||
new_authorized: None,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let vote_account = rpc_client
|
||||
.get_account(&vote_account_keypair.pubkey())
|
||||
.unwrap();
|
||||
let vote_state: VoteStateVersions = vote_account.state().unwrap();
|
||||
let authorized_withdrawer = vote_state.convert_to_current().authorized_withdrawer;
|
||||
assert_eq!(authorized_withdrawer, first_withdraw_authority.pubkey());
|
||||
|
||||
// Authorize vote account withdrawal to another signer with checked instruction
|
||||
let withdraw_authority = Keypair::new();
|
||||
config.signers = vec![&default_signer, &first_withdraw_authority];
|
||||
config.command = CliCommand::VoteAuthorize {
|
||||
vote_account_pubkey,
|
||||
new_authorized_pubkey: withdraw_authority.pubkey(),
|
||||
vote_authorize: VoteAuthorize::Withdrawer,
|
||||
memo: None,
|
||||
authorized: 1,
|
||||
new_authorized: Some(1),
|
||||
};
|
||||
process_command(&config).unwrap_err(); // unsigned by new authority should fail
|
||||
config.signers = vec![
|
||||
&default_signer,
|
||||
&first_withdraw_authority,
|
||||
&withdraw_authority,
|
||||
];
|
||||
config.command = CliCommand::VoteAuthorize {
|
||||
vote_account_pubkey,
|
||||
new_authorized_pubkey: withdraw_authority.pubkey(),
|
||||
vote_authorize: VoteAuthorize::Withdrawer,
|
||||
memo: None,
|
||||
authorized: 1,
|
||||
new_authorized: Some(2),
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let vote_account = rpc_client
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-client"
|
||||
version = "1.7.14"
|
||||
version = "1.6.28"
|
||||
description = "Solana Client"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -24,14 +24,14 @@ semver = "0.11.0"
|
||||
serde = "1.0.122"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.56"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.7.14" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.7.14" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.7.14" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.7.14" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.14" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.7.14" }
|
||||
solana-version = { path = "../version", version = "=1.7.14" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.7.14" }
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.28" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.28" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.28" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.28" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.28" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.28" }
|
||||
solana-version = { path = "../version", version = "=1.6.28" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.28" }
|
||||
thiserror = "1.0"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tungstenite = "0.10.1"
|
||||
@@ -40,7 +40,7 @@ url = "2.1.1"
|
||||
[dev-dependencies]
|
||||
assert_matches = "1.3.0"
|
||||
jsonrpc-http-server = "18.0.0"
|
||||
solana-logger = { path = "../logger", version = "=1.7.14" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.28" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -122,10 +122,10 @@ mod tests {
|
||||
use crate::{
|
||||
blockhash_query,
|
||||
rpc_request::RpcRequest,
|
||||
rpc_response::{Response, RpcFeeCalculator, RpcFees, RpcResponseContext},
|
||||
rpc_response::{Response, RpcFeeCalculator, RpcResponseContext},
|
||||
};
|
||||
use clap::App;
|
||||
use serde_json::{self, json};
|
||||
use serde_json::{self, json, Value};
|
||||
use solana_account_decoder::{UiAccount, UiAccountEncoding};
|
||||
use solana_sdk::{account::Account, hash::hash, nonce, system_program};
|
||||
use std::collections::HashMap;
|
||||
@@ -288,12 +288,10 @@ mod tests {
|
||||
let rpc_fee_calc = FeeCalculator::new(42);
|
||||
let get_recent_blockhash_response = json!(Response {
|
||||
context: RpcResponseContext { slot: 1 },
|
||||
value: json!(RpcFees {
|
||||
blockhash: rpc_blockhash.to_string(),
|
||||
fee_calculator: rpc_fee_calc.clone(),
|
||||
last_valid_slot: 42,
|
||||
last_valid_block_height: 42,
|
||||
}),
|
||||
value: json!((
|
||||
Value::String(rpc_blockhash.to_string()),
|
||||
serde_json::to_value(rpc_fee_calc.clone()).unwrap()
|
||||
)),
|
||||
});
|
||||
let get_fee_calculator_for_blockhash_response = json!(Response {
|
||||
context: RpcResponseContext { slot: 1 },
|
||||
@@ -302,7 +300,10 @@ mod tests {
|
||||
}),
|
||||
});
|
||||
let mut mocks = HashMap::new();
|
||||
mocks.insert(RpcRequest::GetFees, get_recent_blockhash_response.clone());
|
||||
mocks.insert(
|
||||
RpcRequest::GetRecentBlockhash,
|
||||
get_recent_blockhash_response.clone(),
|
||||
);
|
||||
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
|
||||
assert_eq!(
|
||||
BlockhashQuery::default()
|
||||
@@ -311,7 +312,10 @@ mod tests {
|
||||
(rpc_blockhash, rpc_fee_calc.clone()),
|
||||
);
|
||||
let mut mocks = HashMap::new();
|
||||
mocks.insert(RpcRequest::GetFees, get_recent_blockhash_response.clone());
|
||||
mocks.insert(
|
||||
RpcRequest::GetRecentBlockhash,
|
||||
get_recent_blockhash_response.clone(),
|
||||
);
|
||||
mocks.insert(
|
||||
RpcRequest::GetFeeCalculatorForBlockhash,
|
||||
get_fee_calculator_for_blockhash_response,
|
||||
@@ -324,7 +328,10 @@ mod tests {
|
||||
(test_blockhash, rpc_fee_calc),
|
||||
);
|
||||
let mut mocks = HashMap::new();
|
||||
mocks.insert(RpcRequest::GetFees, get_recent_blockhash_response);
|
||||
mocks.insert(
|
||||
RpcRequest::GetRecentBlockhash,
|
||||
get_recent_blockhash_response,
|
||||
);
|
||||
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
|
||||
assert_eq!(
|
||||
BlockhashQuery::None(test_blockhash)
|
||||
|
9
client/src/fees.rs
Normal file
9
client/src/fees.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
use crate::{fee_calculator::FeeCalculator, hash::Hash};
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Fees {
|
||||
pub blockhash: Hash,
|
||||
pub fee_calculator: FeeCalculator,
|
||||
pub last_valid_block_height: u64,
|
||||
}
|
@@ -1,12 +1,10 @@
|
||||
//! The standard [`RpcSender`] over HTTP.
|
||||
|
||||
use {
|
||||
crate::{
|
||||
client_error::Result,
|
||||
rpc_custom_error,
|
||||
rpc_request::{RpcError, RpcRequest, RpcResponseErrorData},
|
||||
rpc_response::RpcSimulateTransactionResult,
|
||||
rpc_sender::*,
|
||||
rpc_sender::RpcSender,
|
||||
},
|
||||
log::*,
|
||||
reqwest::{
|
||||
@@ -17,10 +15,10 @@ use {
|
||||
std::{
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
Arc, RwLock,
|
||||
Arc,
|
||||
},
|
||||
thread::sleep,
|
||||
time::{Duration, Instant},
|
||||
time::Duration,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -28,22 +26,13 @@ pub struct HttpSender {
|
||||
client: Arc<reqwest::blocking::Client>,
|
||||
url: String,
|
||||
request_id: AtomicU64,
|
||||
stats: RwLock<RpcTransportStats>,
|
||||
}
|
||||
|
||||
/// The standard [`RpcSender`] over HTTP.
|
||||
impl HttpSender {
|
||||
/// Create an HTTP RPC sender.
|
||||
///
|
||||
/// The URL is an HTTP URL, usually for port 8899, as in
|
||||
/// "http://localhost:8899". The sender has a default timeout of 30 seconds.
|
||||
pub fn new(url: String) -> Self {
|
||||
Self::new_with_timeout(url, Duration::from_secs(30))
|
||||
}
|
||||
|
||||
/// Create an HTTP RPC sender.
|
||||
///
|
||||
/// The URL is an HTTP URL, usually for port 8899.
|
||||
pub fn new_with_timeout(url: String, timeout: Duration) -> Self {
|
||||
// `reqwest::blocking::Client` panics if run in a tokio async context. Shuttle the
|
||||
// request to a different tokio thread to avoid this
|
||||
@@ -60,7 +49,6 @@ impl HttpSender {
|
||||
client,
|
||||
url,
|
||||
request_id: AtomicU64::new(0),
|
||||
stats: RwLock::new(RpcTransportStats::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,45 +57,11 @@ impl HttpSender {
|
||||
struct RpcErrorObject {
|
||||
code: i64,
|
||||
message: String,
|
||||
}
|
||||
|
||||
struct StatsUpdater<'a> {
|
||||
stats: &'a RwLock<RpcTransportStats>,
|
||||
request_start_time: Instant,
|
||||
rate_limited_time: Duration,
|
||||
}
|
||||
|
||||
impl<'a> StatsUpdater<'a> {
|
||||
fn new(stats: &'a RwLock<RpcTransportStats>) -> Self {
|
||||
Self {
|
||||
stats,
|
||||
request_start_time: Instant::now(),
|
||||
rate_limited_time: Duration::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_rate_limited_time(&mut self, duration: Duration) {
|
||||
self.rate_limited_time += duration;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for StatsUpdater<'a> {
|
||||
fn drop(&mut self) {
|
||||
let mut stats = self.stats.write().unwrap();
|
||||
stats.request_count += 1;
|
||||
stats.elapsed_time += Instant::now().duration_since(self.request_start_time);
|
||||
stats.rate_limited_time += self.rate_limited_time;
|
||||
}
|
||||
data: serde_json::Value,
|
||||
}
|
||||
|
||||
impl RpcSender for HttpSender {
|
||||
fn get_transport_stats(&self) -> RpcTransportStats {
|
||||
self.stats.read().unwrap().clone()
|
||||
}
|
||||
|
||||
fn send(&self, request: RpcRequest, params: serde_json::Value) -> Result<serde_json::Value> {
|
||||
let mut stats_updater = StatsUpdater::new(&self.stats);
|
||||
|
||||
let request_id = self.request_id.fetch_add(1, Ordering::Relaxed);
|
||||
let request_json = request.build_request_json(request_id, params).to_string();
|
||||
|
||||
@@ -125,42 +79,45 @@ impl RpcSender for HttpSender {
|
||||
.body(request_json)
|
||||
.send()
|
||||
})
|
||||
}?;
|
||||
};
|
||||
|
||||
if !response.status().is_success() {
|
||||
if response.status() == StatusCode::TOO_MANY_REQUESTS
|
||||
&& too_many_requests_retries > 0
|
||||
{
|
||||
let mut duration = Duration::from_millis(500);
|
||||
if let Some(retry_after) = response.headers().get(RETRY_AFTER) {
|
||||
if let Ok(retry_after) = retry_after.to_str() {
|
||||
if let Ok(retry_after) = retry_after.parse::<u64>() {
|
||||
if retry_after < 120 {
|
||||
duration = Duration::from_secs(retry_after);
|
||||
match response {
|
||||
Ok(response) => {
|
||||
if !response.status().is_success() {
|
||||
if response.status() == StatusCode::TOO_MANY_REQUESTS
|
||||
&& too_many_requests_retries > 0
|
||||
{
|
||||
let mut duration = Duration::from_millis(500);
|
||||
if let Some(retry_after) = response.headers().get(RETRY_AFTER) {
|
||||
if let Ok(retry_after) = retry_after.to_str() {
|
||||
if let Ok(retry_after) = retry_after.parse::<u64>() {
|
||||
if retry_after < 120 {
|
||||
duration = Duration::from_secs(retry_after);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
too_many_requests_retries -= 1;
|
||||
debug!(
|
||||
too_many_requests_retries -= 1;
|
||||
debug!(
|
||||
"Too many requests: server responded with {:?}, {} retries left, pausing for {:?}",
|
||||
response, too_many_requests_retries, duration
|
||||
);
|
||||
|
||||
sleep(duration);
|
||||
stats_updater.add_rate_limited_time(duration);
|
||||
continue;
|
||||
}
|
||||
return Err(response.error_for_status().unwrap_err().into());
|
||||
}
|
||||
sleep(duration);
|
||||
continue;
|
||||
}
|
||||
return Err(response.error_for_status().unwrap_err().into());
|
||||
}
|
||||
|
||||
let mut json =
|
||||
tokio::task::block_in_place(move || response.json::<serde_json::Value>())?;
|
||||
if json["error"].is_object() {
|
||||
return match serde_json::from_value::<RpcErrorObject>(json["error"].clone()) {
|
||||
Ok(rpc_error_object) => {
|
||||
let data = match rpc_error_object.code {
|
||||
let response_text = tokio::task::block_in_place(move || response.text())?;
|
||||
|
||||
let json: serde_json::Value = serde_json::from_str(&response_text)?;
|
||||
if json["error"].is_object() {
|
||||
return match serde_json::from_value::<RpcErrorObject>(json["error"].clone())
|
||||
{
|
||||
Ok(rpc_error_object) => {
|
||||
let data = match rpc_error_object.code {
|
||||
rpc_custom_error::JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE => {
|
||||
match serde_json::from_value::<RpcSimulateTransactionResult>(json["error"]["data"].clone()) {
|
||||
Ok(data) => RpcResponseErrorData::SendTransactionPreflightFailure(data),
|
||||
@@ -181,22 +138,27 @@ impl RpcSender for HttpSender {
|
||||
_ => RpcResponseErrorData::Empty
|
||||
};
|
||||
|
||||
Err(RpcError::RpcResponseError {
|
||||
code: rpc_error_object.code,
|
||||
message: rpc_error_object.message,
|
||||
data,
|
||||
}
|
||||
.into())
|
||||
Err(RpcError::RpcResponseError {
|
||||
code: rpc_error_object.code,
|
||||
message: rpc_error_object.message,
|
||||
data,
|
||||
}
|
||||
.into())
|
||||
}
|
||||
Err(err) => Err(RpcError::RpcRequestError(format!(
|
||||
"Failed to deserialize RPC error response: {} [{}]",
|
||||
serde_json::to_string(&json["error"]).unwrap(),
|
||||
err
|
||||
))
|
||||
.into()),
|
||||
};
|
||||
}
|
||||
Err(err) => Err(RpcError::RpcRequestError(format!(
|
||||
"Failed to deserialize RPC error response: {} [{}]",
|
||||
serde_json::to_string(&json["error"]).unwrap(),
|
||||
err
|
||||
))
|
||||
.into()),
|
||||
};
|
||||
return Ok(json["result"].clone());
|
||||
}
|
||||
Err(err) => {
|
||||
return Err(err.into());
|
||||
}
|
||||
}
|
||||
return Ok(json["result"].take());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -13,7 +13,6 @@ pub mod rpc_cache;
|
||||
pub mod rpc_client;
|
||||
pub mod rpc_config;
|
||||
pub mod rpc_custom_error;
|
||||
pub mod rpc_deprecated_config;
|
||||
pub mod rpc_filter;
|
||||
pub mod rpc_request;
|
||||
pub mod rpc_response;
|
||||
|
@@ -1,42 +1,21 @@
|
||||
//! An [`RpcSender`] used for unit testing [`RpcClient`](crate::rpc_client::RpcClient).
|
||||
|
||||
use {
|
||||
crate::{
|
||||
client_error::Result,
|
||||
rpc_config::RpcBlockProductionConfig,
|
||||
rpc_request::RpcRequest,
|
||||
rpc_response::{
|
||||
Response, RpcAccountBalance, RpcBlockProduction, RpcBlockProductionRange,
|
||||
RpcConfirmedTransactionStatusWithSignature, RpcContactInfo, RpcFees, RpcIdentity,
|
||||
RpcInflationGovernor, RpcInflationRate, RpcInflationReward, RpcKeyedAccount,
|
||||
RpcPerfSample, RpcResponseContext, RpcSimulateTransactionResult, RpcStakeActivation,
|
||||
RpcSupply, RpcVersionInfo, RpcVoteAccountInfo, RpcVoteAccountStatus,
|
||||
StakeActivationState,
|
||||
},
|
||||
rpc_sender::*,
|
||||
rpc_response::{Response, RpcResponseContext, RpcVersionInfo},
|
||||
rpc_sender::RpcSender,
|
||||
},
|
||||
serde_json::{json, Number, Value},
|
||||
solana_account_decoder::{UiAccount, UiAccountEncoding},
|
||||
solana_sdk::{
|
||||
account::Account,
|
||||
clock::{Slot, UnixTimestamp},
|
||||
epoch_info::EpochInfo,
|
||||
fee_calculator::{FeeCalculator, FeeRateGovernor},
|
||||
instruction::InstructionError,
|
||||
message::MessageHeader,
|
||||
pubkey::Pubkey,
|
||||
signature::Signature,
|
||||
sysvar::epoch_schedule::EpochSchedule,
|
||||
transaction::{self, Transaction, TransactionError},
|
||||
},
|
||||
solana_transaction_status::{
|
||||
EncodedConfirmedBlock, EncodedConfirmedTransaction, EncodedTransaction,
|
||||
EncodedTransactionWithStatusMeta, Rewards, TransactionConfirmationStatus,
|
||||
TransactionStatus, UiCompiledInstruction, UiMessage, UiRawMessage, UiTransaction,
|
||||
UiTransactionEncoding, UiTransactionStatusMeta,
|
||||
},
|
||||
solana_transaction_status::{TransactionConfirmationStatus, TransactionStatus},
|
||||
solana_version::Version,
|
||||
std::{collections::HashMap, net::SocketAddr, str::FromStr, sync::RwLock},
|
||||
std::{collections::HashMap, sync::RwLock},
|
||||
};
|
||||
|
||||
pub const PUBKEY: &str = "7RoSF9fUmdphVCpabEoefH81WwrW7orsWonXWqTXkKV8";
|
||||
@@ -49,31 +28,6 @@ pub struct MockSender {
|
||||
url: String,
|
||||
}
|
||||
|
||||
/// An [`RpcSender`] used for unit testing [`RpcClient`](crate::rpc_client::RpcClient).
|
||||
///
|
||||
/// This is primarily for internal use.
|
||||
///
|
||||
/// Unless directed otherwise, it will generally return a reasonable default
|
||||
/// response, at least for [`RpcRequest`] values for which responses have been
|
||||
/// implemented.
|
||||
///
|
||||
/// The behavior can be customized in two ways:
|
||||
///
|
||||
/// 1) The `url` constructor argument is not actually a URL, but a simple string
|
||||
/// directive that changes `MockSender`s behavior in specific scenarios.
|
||||
///
|
||||
/// If `url` is "fails" then any call to `send` will return `Ok(Value::Null)`.
|
||||
///
|
||||
/// It is customary to set the `url` to "succeeds" for mocks that should
|
||||
/// return sucessfully, though this value is not actually interpreted.
|
||||
///
|
||||
/// Other possible values of `url` are specific to different `RpcRequest`
|
||||
/// values. Read the implementation for specifics.
|
||||
///
|
||||
/// 2) Custom responses can be configured by providing [`Mocks`] to the
|
||||
/// [`MockSender::new_with_mocks`] constructor. This type is a [`HashMap`]
|
||||
/// from [`RpcRequest`] to a JSON [`Value`] response, Any entries in this map
|
||||
/// override the default behavior for the given request.
|
||||
impl MockSender {
|
||||
pub fn new(url: String) -> Self {
|
||||
Self::new_with_mocks(url, Mocks::default())
|
||||
@@ -88,10 +42,6 @@ impl MockSender {
|
||||
}
|
||||
|
||||
impl RpcSender for MockSender {
|
||||
fn get_transport_stats(&self) -> RpcTransportStats {
|
||||
RpcTransportStats::default()
|
||||
}
|
||||
|
||||
fn send(&self, request: RpcRequest, params: serde_json::Value) -> Result<serde_json::Value> {
|
||||
if let Some(value) = self.mocks.write().unwrap().remove(&request) {
|
||||
return Ok(value);
|
||||
@@ -99,26 +49,23 @@ impl RpcSender for MockSender {
|
||||
if self.url == "fails" {
|
||||
return Ok(Value::Null);
|
||||
}
|
||||
|
||||
let method = &request.build_request_json(42, params.clone())["method"];
|
||||
|
||||
let val = match method.as_str().unwrap() {
|
||||
"getAccountInfo" => serde_json::to_value(Response {
|
||||
let val = match request {
|
||||
RpcRequest::GetAccountInfo => serde_json::to_value(Response {
|
||||
context: RpcResponseContext { slot: 1 },
|
||||
value: Value::Null,
|
||||
})?,
|
||||
"getBalance" => serde_json::to_value(Response {
|
||||
RpcRequest::GetBalance => serde_json::to_value(Response {
|
||||
context: RpcResponseContext { slot: 1 },
|
||||
value: Value::Number(Number::from(50)),
|
||||
})?,
|
||||
"getRecentBlockhash" => serde_json::to_value(Response {
|
||||
RpcRequest::GetRecentBlockhash => serde_json::to_value(Response {
|
||||
context: RpcResponseContext { slot: 1 },
|
||||
value: (
|
||||
Value::String(PUBKEY.to_string()),
|
||||
serde_json::to_value(FeeCalculator::default()).unwrap(),
|
||||
),
|
||||
})?,
|
||||
"getEpochInfo" => serde_json::to_value(EpochInfo {
|
||||
RpcRequest::GetEpochInfo => serde_json::to_value(EpochInfo {
|
||||
epoch: 1,
|
||||
slot_index: 2,
|
||||
slots_in_epoch: 32,
|
||||
@@ -126,7 +73,7 @@ impl RpcSender for MockSender {
|
||||
block_height: 34,
|
||||
transaction_count: Some(123),
|
||||
})?,
|
||||
"getFeeCalculatorForBlockhash" => {
|
||||
RpcRequest::GetFeeCalculatorForBlockhash => {
|
||||
let value = if self.url == "blockhash_expired" {
|
||||
Value::Null
|
||||
} else {
|
||||
@@ -137,21 +84,11 @@ impl RpcSender for MockSender {
|
||||
value,
|
||||
})?
|
||||
}
|
||||
"getFeeRateGovernor" => serde_json::to_value(Response {
|
||||
RpcRequest::GetFeeRateGovernor => serde_json::to_value(Response {
|
||||
context: RpcResponseContext { slot: 1 },
|
||||
value: serde_json::to_value(FeeRateGovernor::default()).unwrap(),
|
||||
})?,
|
||||
"getFees" => serde_json::to_value(Response {
|
||||
context: RpcResponseContext { slot: 1 },
|
||||
value: serde_json::to_value(RpcFees {
|
||||
blockhash: PUBKEY.to_string(),
|
||||
fee_calculator: FeeCalculator::default(),
|
||||
last_valid_slot: 42,
|
||||
last_valid_block_height: 42,
|
||||
})
|
||||
.unwrap(),
|
||||
})?,
|
||||
"getSignatureStatuses" => {
|
||||
RpcRequest::GetSignatureStatuses => {
|
||||
let status: transaction::Result<()> = if self.url == "account_in_use" {
|
||||
Err(TransactionError::AccountInUse)
|
||||
} else if self.url == "instruction_error" {
|
||||
@@ -185,133 +122,11 @@ impl RpcSender for MockSender {
|
||||
value: statuses,
|
||||
})?
|
||||
}
|
||||
"getTransaction" => serde_json::to_value(EncodedConfirmedTransaction {
|
||||
slot: 2,
|
||||
transaction: EncodedTransactionWithStatusMeta {
|
||||
transaction: EncodedTransaction::Json(
|
||||
UiTransaction {
|
||||
signatures: vec!["3AsdoALgZFuq2oUVWrDYhg2pNeaLJKPLf8hU2mQ6U8qJxeJ6hsrPVpMn9ma39DtfYCrDQSvngWRP8NnTpEhezJpE".to_string()],
|
||||
message: UiMessage::Raw(
|
||||
UiRawMessage {
|
||||
header: MessageHeader {
|
||||
num_required_signatures: 1,
|
||||
num_readonly_signed_accounts: 0,
|
||||
num_readonly_unsigned_accounts: 1,
|
||||
},
|
||||
account_keys: vec![
|
||||
"C6eBmAXKg6JhJWkajGa5YRGUfG4YKXwbxF5Ufv7PtExZ".to_string(),
|
||||
"2Gd5eoR5J4BV89uXbtunpbNhjmw3wa1NbRHxTHzDzZLX".to_string(),
|
||||
"11111111111111111111111111111111".to_string(),
|
||||
],
|
||||
recent_blockhash: "D37n3BSG71oUWcWjbZ37jZP7UfsxG2QMKeuALJ1PYvM6".to_string(),
|
||||
instructions: vec![UiCompiledInstruction {
|
||||
program_id_index: 2,
|
||||
accounts: vec![0, 1],
|
||||
data: "3Bxs49DitAvXtoDR".to_string(),
|
||||
}],
|
||||
})
|
||||
}),
|
||||
meta: Some(UiTransactionStatusMeta {
|
||||
err: None,
|
||||
status: Ok(()),
|
||||
fee: 0,
|
||||
pre_balances: vec![499999999999999950, 50, 1],
|
||||
post_balances: vec![499999999999999950, 50, 1],
|
||||
inner_instructions: None,
|
||||
log_messages: None,
|
||||
pre_token_balances: None,
|
||||
post_token_balances: None,
|
||||
rewards: None,
|
||||
}),
|
||||
},
|
||||
block_time: Some(1628633791),
|
||||
})?,
|
||||
"getTransactionCount" => json![1234],
|
||||
"getSlot" => json![0],
|
||||
"getMaxShredInsertSlot" => json![0],
|
||||
"requestAirdrop" => Value::String(Signature::new(&[8; 64]).to_string()),
|
||||
"getSnapshotSlot" => Value::Number(Number::from(0)),
|
||||
"getBlockHeight" => Value::Number(Number::from(1234)),
|
||||
"getSlotLeaders" => json!([PUBKEY]),
|
||||
"getBlockProduction" => {
|
||||
if params.is_null() {
|
||||
json!(Response {
|
||||
context: RpcResponseContext { slot: 1 },
|
||||
value: RpcBlockProduction {
|
||||
by_identity: HashMap::new(),
|
||||
range: RpcBlockProductionRange {
|
||||
first_slot: 1,
|
||||
last_slot: 2,
|
||||
},
|
||||
},
|
||||
})
|
||||
} else {
|
||||
let config: Vec<RpcBlockProductionConfig> =
|
||||
serde_json::from_value(params).unwrap();
|
||||
let config = config[0].clone();
|
||||
let mut by_identity = HashMap::new();
|
||||
by_identity.insert(config.identity.unwrap(), (1, 123));
|
||||
let config_range = config.range.unwrap_or_default();
|
||||
|
||||
json!(Response {
|
||||
context: RpcResponseContext { slot: 1 },
|
||||
value: RpcBlockProduction {
|
||||
by_identity,
|
||||
range: RpcBlockProductionRange {
|
||||
first_slot: config_range.first_slot,
|
||||
last_slot: {
|
||||
if let Some(last_slot) = config_range.last_slot {
|
||||
last_slot
|
||||
} else {
|
||||
2
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
"getStakeActivation" => json!(RpcStakeActivation {
|
||||
state: StakeActivationState::Activating,
|
||||
active: 123,
|
||||
inactive: 12,
|
||||
}),
|
||||
"getSupply" => json!(Response {
|
||||
context: RpcResponseContext { slot: 1 },
|
||||
value: RpcSupply {
|
||||
total: 100000000,
|
||||
circulating: 50000,
|
||||
non_circulating: 20000,
|
||||
non_circulating_accounts: vec![PUBKEY.to_string()],
|
||||
},
|
||||
}),
|
||||
"getLargestAccounts" => {
|
||||
let rpc_account_balance = RpcAccountBalance {
|
||||
address: PUBKEY.to_string(),
|
||||
lamports: 10000,
|
||||
};
|
||||
|
||||
json!(Response {
|
||||
context: RpcResponseContext { slot: 1 },
|
||||
value: vec![rpc_account_balance],
|
||||
})
|
||||
}
|
||||
"getVoteAccounts" => {
|
||||
json!(RpcVoteAccountStatus {
|
||||
current: vec![],
|
||||
delinquent: vec![RpcVoteAccountInfo {
|
||||
vote_pubkey: PUBKEY.to_string(),
|
||||
node_pubkey: PUBKEY.to_string(),
|
||||
activated_stake: 0,
|
||||
commission: 0,
|
||||
epoch_vote_account: false,
|
||||
epoch_credits: vec![],
|
||||
last_vote: 0,
|
||||
root_slot: Slot::default(),
|
||||
}],
|
||||
})
|
||||
}
|
||||
"sendTransaction" => {
|
||||
RpcRequest::GetTransactionCount => Value::Number(Number::from(1234)),
|
||||
RpcRequest::GetSlot => Value::Number(Number::from(0)),
|
||||
RpcRequest::GetMaxShredInsertSlot => Value::Number(Number::from(0)),
|
||||
RpcRequest::RequestAirdrop => Value::String(Signature::new(&[8; 64]).to_string()),
|
||||
RpcRequest::SendTransaction => {
|
||||
let signature = if self.url == "malicious" {
|
||||
Signature::new(&[8; 64]).to_string()
|
||||
} else {
|
||||
@@ -322,124 +137,14 @@ impl RpcSender for MockSender {
|
||||
};
|
||||
Value::String(signature)
|
||||
}
|
||||
"simulateTransaction" => serde_json::to_value(Response {
|
||||
context: RpcResponseContext { slot: 1 },
|
||||
value: RpcSimulateTransactionResult {
|
||||
err: None,
|
||||
logs: None,
|
||||
accounts: None,
|
||||
},
|
||||
})?,
|
||||
"getMinimumBalanceForRentExemption" => json![20],
|
||||
"getVersion" => {
|
||||
RpcRequest::GetMinimumBalanceForRentExemption => Value::Number(Number::from(20)),
|
||||
RpcRequest::GetVersion => {
|
||||
let version = Version::default();
|
||||
json!(RpcVersionInfo {
|
||||
solana_core: version.to_string(),
|
||||
feature_set: Some(version.feature_set),
|
||||
})
|
||||
}
|
||||
"getClusterNodes" => serde_json::to_value(vec![RpcContactInfo {
|
||||
pubkey: PUBKEY.to_string(),
|
||||
gossip: Some(SocketAddr::from(([10, 239, 6, 48], 8899))),
|
||||
tpu: Some(SocketAddr::from(([10, 239, 6, 48], 8856))),
|
||||
rpc: Some(SocketAddr::from(([10, 239, 6, 48], 8899))),
|
||||
version: Some("1.0.0 c375ce1f".to_string()),
|
||||
feature_set: None,
|
||||
shred_version: None,
|
||||
}])?,
|
||||
"getBlock" => serde_json::to_value(EncodedConfirmedBlock {
|
||||
previous_blockhash: "mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B".to_string(),
|
||||
blockhash: "3Eq21vXNB5s86c62bVuUfTeaMif1N2kUqRPBmGRJhyTA".to_string(),
|
||||
parent_slot: 429,
|
||||
transactions: vec![EncodedTransactionWithStatusMeta {
|
||||
transaction: EncodedTransaction::Binary(
|
||||
"ju9xZWuDBX4pRxX2oZkTjxU5jB4SSTgEGhX8bQ8PURNzyzqKMPPpNvWihx8zUe\
|
||||
FfrbVNoAaEsNKZvGzAnTDy5bhNT9kt6KFCTBixpvrLCzg4M5UdFUQYrn1gdgjX\
|
||||
pLHxcaShD81xBNaFDgnA2nkkdHnKtZt4hVSfKAmw3VRZbjrZ7L2fKZBx21CwsG\
|
||||
hD6onjM2M3qZW5C8J6d1pj41MxKmZgPBSha3MyKkNLkAGFASK"
|
||||
.to_string(),
|
||||
UiTransactionEncoding::Base58,
|
||||
),
|
||||
meta: None,
|
||||
}],
|
||||
rewards: Rewards::new(),
|
||||
block_time: None,
|
||||
block_height: Some(428),
|
||||
})?,
|
||||
"getBlocks" => serde_json::to_value(vec![1, 2, 3])?,
|
||||
"getBlocksWithLimit" => serde_json::to_value(vec![1, 2, 3])?,
|
||||
"getSignaturesForAddress" => {
|
||||
serde_json::to_value(vec![RpcConfirmedTransactionStatusWithSignature {
|
||||
signature: SIGNATURE.to_string(),
|
||||
slot: 123,
|
||||
err: None,
|
||||
memo: None,
|
||||
block_time: None,
|
||||
confirmation_status: Some(TransactionConfirmationStatus::Finalized),
|
||||
}])?
|
||||
}
|
||||
"getBlockTime" => serde_json::to_value(UnixTimestamp::default())?,
|
||||
"getEpochSchedule" => serde_json::to_value(EpochSchedule::default())?,
|
||||
"getRecentPerformanceSamples" => serde_json::to_value(vec![RpcPerfSample {
|
||||
slot: 347873,
|
||||
num_transactions: 125,
|
||||
num_slots: 123,
|
||||
sample_period_secs: 60,
|
||||
}])?,
|
||||
"getIdentity" => serde_json::to_value(RpcIdentity {
|
||||
identity: PUBKEY.to_string(),
|
||||
})?,
|
||||
"getInflationGovernor" => serde_json::to_value(
|
||||
RpcInflationGovernor {
|
||||
initial: 0.08,
|
||||
terminal: 0.015,
|
||||
taper: 0.15,
|
||||
foundation: 0.05,
|
||||
foundation_term: 7.0,
|
||||
})?,
|
||||
"getInflationRate" => serde_json::to_value(
|
||||
RpcInflationRate {
|
||||
total: 0.08,
|
||||
validator: 0.076,
|
||||
foundation: 0.004,
|
||||
epoch: 0,
|
||||
})?,
|
||||
"getInflationReward" => serde_json::to_value(vec![
|
||||
Some(RpcInflationReward {
|
||||
epoch: 2,
|
||||
effective_slot: 224,
|
||||
amount: 2500,
|
||||
post_balance: 499999442500,
|
||||
commission: None,
|
||||
})])?,
|
||||
"minimumLedgerSlot" => json![123],
|
||||
"getMaxRetransmitSlot" => json![123],
|
||||
"getMultipleAccounts" => serde_json::to_value(Response {
|
||||
context: RpcResponseContext { slot: 1 },
|
||||
value: vec![Value::Null, Value::Null]
|
||||
})?,
|
||||
"getProgramAccounts" => {
|
||||
let pubkey = Pubkey::from_str(&PUBKEY.to_string()).unwrap();
|
||||
let account = Account {
|
||||
lamports: 1_000_000,
|
||||
data: vec![],
|
||||
owner: pubkey,
|
||||
executable: false,
|
||||
rent_epoch: 0,
|
||||
};
|
||||
serde_json::to_value(vec![
|
||||
RpcKeyedAccount {
|
||||
pubkey: PUBKEY.to_string(),
|
||||
account: UiAccount::encode(
|
||||
&pubkey,
|
||||
&account,
|
||||
UiAccountEncoding::Base64,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
])?
|
||||
},
|
||||
_ => Value::Null,
|
||||
};
|
||||
Ok(val)
|
||||
|
@@ -22,8 +22,7 @@ use {
|
||||
mpsc::{channel, Receiver},
|
||||
Arc, RwLock,
|
||||
},
|
||||
thread::{sleep, JoinHandle},
|
||||
time::Duration,
|
||||
thread::JoinHandle,
|
||||
},
|
||||
thiserror::Error,
|
||||
tungstenite::{client::AutoStream, connect, Message, WebSocket},
|
||||
@@ -165,28 +164,6 @@ pub type SignatureSubscription = (
|
||||
|
||||
pub struct PubsubClient {}
|
||||
|
||||
fn connect_with_retry(url: Url) -> Result<WebSocket<AutoStream>, tungstenite::Error> {
|
||||
let mut connection_retries = 5;
|
||||
loop {
|
||||
let result = connect(url.clone()).map(|(socket, _)| socket);
|
||||
if let Err(tungstenite::Error::Http(status_code)) = &result {
|
||||
if *status_code == reqwest::StatusCode::TOO_MANY_REQUESTS && connection_retries > 0 {
|
||||
let duration = Duration::from_millis(500) * 2u32.pow(5 - connection_retries);
|
||||
|
||||
connection_retries -= 1;
|
||||
debug!(
|
||||
"Too many requests: server responded with {:?}, {} retries left, pausing for {:?}",
|
||||
status_code, connection_retries, duration
|
||||
);
|
||||
|
||||
sleep(duration);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
impl PubsubClient {
|
||||
pub fn logs_subscribe(
|
||||
url: &str,
|
||||
@@ -194,7 +171,7 @@ impl PubsubClient {
|
||||
config: RpcTransactionLogsConfig,
|
||||
) -> Result<LogsSubscription, PubsubClientError> {
|
||||
let url = Url::parse(url)?;
|
||||
let socket = connect_with_retry(url)?;
|
||||
let (socket, _response) = connect(url)?;
|
||||
let (sender, receiver) = channel();
|
||||
|
||||
let socket = Arc::new(RwLock::new(socket));
|
||||
@@ -249,7 +226,7 @@ impl PubsubClient {
|
||||
|
||||
pub fn slot_subscribe(url: &str) -> Result<SlotsSubscription, PubsubClientError> {
|
||||
let url = Url::parse(url)?;
|
||||
let socket = connect_with_retry(url)?;
|
||||
let (socket, _response) = connect(url)?;
|
||||
let (sender, receiver) = channel::<SlotInfo>();
|
||||
|
||||
let socket = Arc::new(RwLock::new(socket));
|
||||
@@ -305,7 +282,7 @@ impl PubsubClient {
|
||||
config: Option<RpcSignatureSubscribeConfig>,
|
||||
) -> Result<SignatureSubscription, PubsubClientError> {
|
||||
let url = Url::parse(url)?;
|
||||
let socket = connect_with_retry(url)?;
|
||||
let (socket, _response) = connect(url)?;
|
||||
let (sender, receiver) = channel();
|
||||
|
||||
let socket = Arc::new(RwLock::new(socket));
|
||||
@@ -371,7 +348,7 @@ impl PubsubClient {
|
||||
handler: impl Fn(SlotUpdate) + Send + 'static,
|
||||
) -> Result<PubsubClientSubscription<SlotUpdate>, PubsubClientError> {
|
||||
let url = Url::parse(url)?;
|
||||
let socket = connect_with_retry(url)?;
|
||||
let (socket, _response) = connect(url)?;
|
||||
|
||||
let socket = Arc::new(RwLock::new(socket));
|
||||
let exit = Arc::new(AtomicBool::new(false));
|
||||
|
@@ -31,7 +31,7 @@ impl LargestAccountsCache {
|
||||
&self,
|
||||
filter: &Option<RpcLargestAccountsFilter>,
|
||||
) -> Option<(u64, Vec<RpcAccountBalance>)> {
|
||||
self.cache.get(filter).and_then(|value| {
|
||||
self.cache.get(&filter).and_then(|value| {
|
||||
if let Ok(elapsed) = value.cached_time.elapsed() {
|
||||
if elapsed < Duration::from_secs(self.duration) {
|
||||
return Some((value.slot, value.accounts.clone()));
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -117,15 +117,6 @@ pub struct RpcLargestAccountsConfig {
|
||||
pub filter: Option<RpcLargestAccountsFilter>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcSupplyConfig {
|
||||
#[serde(flatten)]
|
||||
pub commitment: Option<CommitmentConfig>,
|
||||
#[serde(default)]
|
||||
pub exclude_non_circulating_accounts_list: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcEpochConfig {
|
||||
@@ -184,7 +175,7 @@ pub struct RpcSignatureSubscribeConfig {
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcSignaturesForAddressConfig {
|
||||
pub struct RpcGetConfirmedSignaturesForAddress2Config {
|
||||
pub before: Option<String>, // Signature as base-58 string
|
||||
pub until: Option<String>, // Signature as base-58 string
|
||||
pub limit: Option<usize>,
|
||||
@@ -206,17 +197,6 @@ impl<T: EncodingConfig + Default + Copy> RpcEncodingConfigWrapper<T> {
|
||||
RpcEncodingConfigWrapper::Current(config) => config.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert<U: EncodingConfig + From<T>>(&self) -> RpcEncodingConfigWrapper<U> {
|
||||
match self {
|
||||
RpcEncodingConfigWrapper::Deprecated(encoding) => {
|
||||
RpcEncodingConfigWrapper::Deprecated(*encoding)
|
||||
}
|
||||
RpcEncodingConfigWrapper::Current(config) => {
|
||||
RpcEncodingConfigWrapper::Current(config.map(|config| config.into()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait EncodingConfig {
|
||||
@@ -225,7 +205,7 @@ pub trait EncodingConfig {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcBlockConfig {
|
||||
pub struct RpcConfirmedBlockConfig {
|
||||
pub encoding: Option<UiTransactionEncoding>,
|
||||
pub transaction_details: Option<TransactionDetails>,
|
||||
pub rewards: Option<bool>,
|
||||
@@ -233,7 +213,7 @@ pub struct RpcBlockConfig {
|
||||
pub commitment: Option<CommitmentConfig>,
|
||||
}
|
||||
|
||||
impl EncodingConfig for RpcBlockConfig {
|
||||
impl EncodingConfig for RpcConfirmedBlockConfig {
|
||||
fn new_with_encoding(encoding: &Option<UiTransactionEncoding>) -> Self {
|
||||
Self {
|
||||
encoding: *encoding,
|
||||
@@ -242,7 +222,7 @@ impl EncodingConfig for RpcBlockConfig {
|
||||
}
|
||||
}
|
||||
|
||||
impl RpcBlockConfig {
|
||||
impl RpcConfirmedBlockConfig {
|
||||
pub fn rewards_only() -> Self {
|
||||
Self {
|
||||
transaction_details: Some(TransactionDetails::None),
|
||||
@@ -259,21 +239,21 @@ impl RpcBlockConfig {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RpcBlockConfig> for RpcEncodingConfigWrapper<RpcBlockConfig> {
|
||||
fn from(config: RpcBlockConfig) -> Self {
|
||||
impl From<RpcConfirmedBlockConfig> for RpcEncodingConfigWrapper<RpcConfirmedBlockConfig> {
|
||||
fn from(config: RpcConfirmedBlockConfig) -> Self {
|
||||
RpcEncodingConfigWrapper::Current(Some(config))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcTransactionConfig {
|
||||
pub struct RpcConfirmedTransactionConfig {
|
||||
pub encoding: Option<UiTransactionEncoding>,
|
||||
#[serde(flatten)]
|
||||
pub commitment: Option<CommitmentConfig>,
|
||||
}
|
||||
|
||||
impl EncodingConfig for RpcTransactionConfig {
|
||||
impl EncodingConfig for RpcConfirmedTransactionConfig {
|
||||
fn new_with_encoding(encoding: &Option<UiTransactionEncoding>) -> Self {
|
||||
Self {
|
||||
encoding: *encoding,
|
||||
@@ -284,16 +264,16 @@ impl EncodingConfig for RpcTransactionConfig {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum RpcBlocksConfigWrapper {
|
||||
pub enum RpcConfirmedBlocksConfigWrapper {
|
||||
EndSlotOnly(Option<Slot>),
|
||||
CommitmentOnly(Option<CommitmentConfig>),
|
||||
}
|
||||
|
||||
impl RpcBlocksConfigWrapper {
|
||||
impl RpcConfirmedBlocksConfigWrapper {
|
||||
pub fn unzip(&self) -> (Option<Slot>, Option<CommitmentConfig>) {
|
||||
match &self {
|
||||
RpcBlocksConfigWrapper::EndSlotOnly(end_slot) => (*end_slot, None),
|
||||
RpcBlocksConfigWrapper::CommitmentOnly(commitment) => (None, *commitment),
|
||||
RpcConfirmedBlocksConfigWrapper::EndSlotOnly(end_slot) => (*end_slot, None),
|
||||
RpcConfirmedBlocksConfigWrapper::CommitmentOnly(commitment) => (None, *commitment),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
//! Implementation defined RPC server errors
|
||||
use thiserror::Error;
|
||||
|
||||
use {
|
||||
crate::rpc_response::RpcSimulateTransactionResult,
|
||||
jsonrpc_core::{Error, ErrorCode},
|
||||
@@ -17,43 +17,35 @@ pub const JSON_RPC_SERVER_ERROR_NO_SNAPSHOT: i64 = -32008;
|
||||
pub const JSON_RPC_SERVER_ERROR_LONG_TERM_STORAGE_SLOT_SKIPPED: i64 = -32009;
|
||||
pub const JSON_RPC_SERVER_ERROR_KEY_EXCLUDED_FROM_SECONDARY_INDEX: i64 = -32010;
|
||||
pub const JSON_RPC_SERVER_ERROR_TRANSACTION_HISTORY_NOT_AVAILABLE: i64 = -32011;
|
||||
pub const JSON_RPC_SCAN_ERROR: i64 = -32012;
|
||||
pub const JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_LEN_MISMATCH: i64 = -32013;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum RpcCustomError {
|
||||
#[error("BlockCleanedUp")]
|
||||
BlockCleanedUp {
|
||||
slot: Slot,
|
||||
first_available_block: Slot,
|
||||
},
|
||||
#[error("SendTransactionPreflightFailure")]
|
||||
SendTransactionPreflightFailure {
|
||||
message: String,
|
||||
result: RpcSimulateTransactionResult,
|
||||
},
|
||||
#[error("TransactionSignatureVerificationFailure")]
|
||||
TransactionSignatureVerificationFailure,
|
||||
#[error("BlockNotAvailable")]
|
||||
BlockNotAvailable { slot: Slot },
|
||||
#[error("NodeUnhealthy")]
|
||||
NodeUnhealthy { num_slots_behind: Option<Slot> },
|
||||
#[error("TransactionPrecompileVerificationFailure")]
|
||||
BlockNotAvailable {
|
||||
slot: Slot,
|
||||
},
|
||||
NodeUnhealthy {
|
||||
num_slots_behind: Option<Slot>,
|
||||
},
|
||||
TransactionPrecompileVerificationFailure(solana_sdk::transaction::TransactionError),
|
||||
#[error("SlotSkipped")]
|
||||
SlotSkipped { slot: Slot },
|
||||
#[error("NoSnapshot")]
|
||||
SlotSkipped {
|
||||
slot: Slot,
|
||||
},
|
||||
NoSnapshot,
|
||||
#[error("LongTermStorageSlotSkipped")]
|
||||
LongTermStorageSlotSkipped { slot: Slot },
|
||||
#[error("KeyExcludedFromSecondaryIndex")]
|
||||
KeyExcludedFromSecondaryIndex { index_key: String },
|
||||
#[error("TransactionHistoryNotAvailable")]
|
||||
LongTermStorageSlotSkipped {
|
||||
slot: Slot,
|
||||
},
|
||||
KeyExcludedFromSecondaryIndex {
|
||||
index_key: String,
|
||||
},
|
||||
TransactionHistoryNotAvailable,
|
||||
#[error("ScanError")]
|
||||
ScanError { message: String },
|
||||
#[error("TransactionSignatureLenMismatch")]
|
||||
TransactionSignatureLenMismatch,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@@ -149,18 +141,6 @@ impl From<RpcCustomError> for Error {
|
||||
message: "Transaction history is not available from this node".to_string(),
|
||||
data: None,
|
||||
},
|
||||
RpcCustomError::ScanError { message } => Self {
|
||||
code: ErrorCode::ServerError(JSON_RPC_SCAN_ERROR),
|
||||
message,
|
||||
data: None,
|
||||
},
|
||||
RpcCustomError::TransactionSignatureLenMismatch => Self {
|
||||
code: ErrorCode::ServerError(
|
||||
JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_LEN_MISMATCH,
|
||||
),
|
||||
message: "Transaction signature length mismatch".to_string(),
|
||||
data: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,120 +0,0 @@
|
||||
#![allow(deprecated)]
|
||||
use {
|
||||
crate::rpc_config::{
|
||||
EncodingConfig, RpcBlockConfig, RpcEncodingConfigWrapper, RpcTransactionConfig,
|
||||
},
|
||||
solana_sdk::{clock::Slot, commitment_config::CommitmentConfig},
|
||||
solana_transaction_status::{TransactionDetails, UiTransactionEncoding},
|
||||
};
|
||||
|
||||
#[deprecated(
|
||||
since = "1.7.0",
|
||||
note = "Please use RpcSignaturesForAddressConfig instead"
|
||||
)]
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcGetConfirmedSignaturesForAddress2Config {
|
||||
pub before: Option<String>, // Signature as base-58 string
|
||||
pub until: Option<String>, // Signature as base-58 string
|
||||
pub limit: Option<usize>,
|
||||
#[serde(flatten)]
|
||||
pub commitment: Option<CommitmentConfig>,
|
||||
}
|
||||
|
||||
#[deprecated(since = "1.7.0", note = "Please use RpcBlockConfig instead")]
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcConfirmedBlockConfig {
|
||||
pub encoding: Option<UiTransactionEncoding>,
|
||||
pub transaction_details: Option<TransactionDetails>,
|
||||
pub rewards: Option<bool>,
|
||||
#[serde(flatten)]
|
||||
pub commitment: Option<CommitmentConfig>,
|
||||
}
|
||||
|
||||
impl EncodingConfig for RpcConfirmedBlockConfig {
|
||||
fn new_with_encoding(encoding: &Option<UiTransactionEncoding>) -> Self {
|
||||
Self {
|
||||
encoding: *encoding,
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RpcConfirmedBlockConfig {
|
||||
pub fn rewards_only() -> Self {
|
||||
Self {
|
||||
transaction_details: Some(TransactionDetails::None),
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rewards_with_commitment(commitment: Option<CommitmentConfig>) -> Self {
|
||||
Self {
|
||||
transaction_details: Some(TransactionDetails::None),
|
||||
commitment,
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RpcConfirmedBlockConfig> for RpcEncodingConfigWrapper<RpcConfirmedBlockConfig> {
|
||||
fn from(config: RpcConfirmedBlockConfig) -> Self {
|
||||
RpcEncodingConfigWrapper::Current(Some(config))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RpcConfirmedBlockConfig> for RpcBlockConfig {
|
||||
fn from(config: RpcConfirmedBlockConfig) -> Self {
|
||||
Self {
|
||||
encoding: config.encoding,
|
||||
transaction_details: config.transaction_details,
|
||||
rewards: config.rewards,
|
||||
commitment: config.commitment,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated(since = "1.7.0", note = "Please use RpcTransactionConfig instead")]
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcConfirmedTransactionConfig {
|
||||
pub encoding: Option<UiTransactionEncoding>,
|
||||
#[serde(flatten)]
|
||||
pub commitment: Option<CommitmentConfig>,
|
||||
}
|
||||
|
||||
impl EncodingConfig for RpcConfirmedTransactionConfig {
|
||||
fn new_with_encoding(encoding: &Option<UiTransactionEncoding>) -> Self {
|
||||
Self {
|
||||
encoding: *encoding,
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RpcConfirmedTransactionConfig> for RpcTransactionConfig {
|
||||
fn from(config: RpcConfirmedTransactionConfig) -> Self {
|
||||
Self {
|
||||
encoding: config.encoding,
|
||||
commitment: config.commitment,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated(since = "1.7.0", note = "Please use RpcBlocksConfigWrapper instead")]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum RpcConfirmedBlocksConfigWrapper {
|
||||
EndSlotOnly(Option<Slot>),
|
||||
CommitmentOnly(Option<CommitmentConfig>),
|
||||
}
|
||||
|
||||
impl RpcConfirmedBlocksConfigWrapper {
|
||||
pub fn unzip(&self) -> (Option<Slot>, Option<CommitmentConfig>) {
|
||||
match &self {
|
||||
RpcConfirmedBlocksConfigWrapper::EndSlotOnly(end_slot) => (*end_slot, None),
|
||||
RpcConfirmedBlocksConfigWrapper::CommitmentOnly(commitment) => (None, *commitment),
|
||||
}
|
||||
}
|
||||
}
|
@@ -11,34 +11,22 @@ pub enum RpcRequest {
|
||||
DeregisterNode,
|
||||
GetAccountInfo,
|
||||
GetBalance,
|
||||
GetBlock,
|
||||
GetBlockHeight,
|
||||
GetBlockProduction,
|
||||
GetBlocks,
|
||||
GetBlocksWithLimit,
|
||||
GetBlockTime,
|
||||
GetClusterNodes,
|
||||
|
||||
#[deprecated(since = "1.7.0", note = "Please use RpcRequest::GetBlock instead")]
|
||||
GetConfirmedBlock,
|
||||
#[deprecated(since = "1.7.0", note = "Please use RpcRequest::GetBlocks instead")]
|
||||
GetConfirmedBlocks,
|
||||
#[deprecated(
|
||||
since = "1.7.0",
|
||||
note = "Please use RpcRequest::GetBlocksWithLimit instead"
|
||||
)]
|
||||
GetConfirmedBlocksWithLimit,
|
||||
#[deprecated(
|
||||
since = "1.7.0",
|
||||
note = "Please use RpcRequest::GetSignaturesForAddress instead"
|
||||
)]
|
||||
GetConfirmedSignaturesForAddress2,
|
||||
#[deprecated(
|
||||
since = "1.7.0",
|
||||
note = "Please use RpcRequest::GetTransaction instead"
|
||||
)]
|
||||
GetConfirmedTransaction,
|
||||
|
||||
#[deprecated(
|
||||
since = "1.5.19",
|
||||
note = "Please use RpcRequest::GetConfirmedSignaturesForAddress2 instead"
|
||||
)]
|
||||
GetConfirmedSignaturesForAddress,
|
||||
|
||||
GetConfirmedSignaturesForAddress2,
|
||||
GetConfirmedTransaction,
|
||||
GetEpochInfo,
|
||||
GetEpochSchedule,
|
||||
GetFeeCalculatorForBlockhash,
|
||||
@@ -61,7 +49,6 @@ pub enum RpcRequest {
|
||||
GetRecentBlockhash,
|
||||
GetRecentPerformanceSamples,
|
||||
GetSnapshotSlot,
|
||||
GetSignaturesForAddress,
|
||||
GetSignatureStatuses,
|
||||
GetSlot,
|
||||
GetSlotLeader,
|
||||
@@ -76,7 +63,10 @@ pub enum RpcRequest {
|
||||
GetTokenAccountsByDelegate,
|
||||
GetTokenAccountsByOwner,
|
||||
GetTokenSupply,
|
||||
GetTransaction,
|
||||
|
||||
#[deprecated(since = "1.5.19", note = "Please use RpcRequest::GetSupply instead")]
|
||||
GetTotalSupply,
|
||||
|
||||
GetTransactionCount,
|
||||
GetVersion,
|
||||
GetVoteAccounts,
|
||||
@@ -86,9 +76,6 @@ pub enum RpcRequest {
|
||||
SendTransaction,
|
||||
SimulateTransaction,
|
||||
SignVote,
|
||||
Custom {
|
||||
method: &'static str,
|
||||
},
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
@@ -98,16 +85,14 @@ impl fmt::Display for RpcRequest {
|
||||
RpcRequest::DeregisterNode => "deregisterNode",
|
||||
RpcRequest::GetAccountInfo => "getAccountInfo",
|
||||
RpcRequest::GetBalance => "getBalance",
|
||||
RpcRequest::GetBlock => "getBlock",
|
||||
RpcRequest::GetBlockHeight => "getBlockHeight",
|
||||
RpcRequest::GetBlockProduction => "getBlockProduction",
|
||||
RpcRequest::GetBlocks => "getBlocks",
|
||||
RpcRequest::GetBlocksWithLimit => "getBlocksWithLimit",
|
||||
RpcRequest::GetBlockTime => "getBlockTime",
|
||||
RpcRequest::GetClusterNodes => "getClusterNodes",
|
||||
RpcRequest::GetConfirmedBlock => "getConfirmedBlock",
|
||||
RpcRequest::GetConfirmedBlocks => "getConfirmedBlocks",
|
||||
RpcRequest::GetConfirmedBlocksWithLimit => "getConfirmedBlocksWithLimit",
|
||||
RpcRequest::GetConfirmedSignaturesForAddress => "getConfirmedSignaturesForAddress",
|
||||
RpcRequest::GetConfirmedSignaturesForAddress2 => "getConfirmedSignaturesForAddress2",
|
||||
RpcRequest::GetConfirmedTransaction => "getConfirmedTransaction",
|
||||
RpcRequest::GetEpochInfo => "getEpochInfo",
|
||||
@@ -132,7 +117,6 @@ impl fmt::Display for RpcRequest {
|
||||
RpcRequest::GetRecentBlockhash => "getRecentBlockhash",
|
||||
RpcRequest::GetRecentPerformanceSamples => "getRecentPerformanceSamples",
|
||||
RpcRequest::GetSnapshotSlot => "getSnapshotSlot",
|
||||
RpcRequest::GetSignaturesForAddress => "getSignaturesForAddress",
|
||||
RpcRequest::GetSignatureStatuses => "getSignatureStatuses",
|
||||
RpcRequest::GetSlot => "getSlot",
|
||||
RpcRequest::GetSlotLeader => "getSlotLeader",
|
||||
@@ -147,7 +131,7 @@ impl fmt::Display for RpcRequest {
|
||||
RpcRequest::GetTokenAccountsByDelegate => "getTokenAccountsByDelegate",
|
||||
RpcRequest::GetTokenAccountsByOwner => "getTokenAccountsByOwner",
|
||||
RpcRequest::GetTokenSupply => "getTokenSupply",
|
||||
RpcRequest::GetTransaction => "getTransaction",
|
||||
RpcRequest::GetTotalSupply => "getTotalSupply",
|
||||
RpcRequest::GetTransactionCount => "getTransactionCount",
|
||||
RpcRequest::GetVersion => "getVersion",
|
||||
RpcRequest::GetVoteAccounts => "getVoteAccounts",
|
||||
@@ -157,7 +141,6 @@ impl fmt::Display for RpcRequest {
|
||||
RpcRequest::SendTransaction => "sendTransaction",
|
||||
RpcRequest::SimulateTransaction => "simulateTransaction",
|
||||
RpcRequest::SignVote => "signVote",
|
||||
RpcRequest::Custom { method } => method,
|
||||
};
|
||||
|
||||
write!(f, "{}", method)
|
||||
|
@@ -1,35 +1,5 @@
|
||||
//! A transport for RPC calls.
|
||||
use crate::{client_error::Result, rpc_request::RpcRequest};
|
||||
|
||||
use {
|
||||
crate::{client_error::Result, rpc_request::RpcRequest},
|
||||
std::time::Duration,
|
||||
};
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct RpcTransportStats {
|
||||
/// Number of RPC requests issued
|
||||
pub request_count: usize,
|
||||
|
||||
/// Total amount of time spent transacting with the RPC server
|
||||
pub elapsed_time: Duration,
|
||||
|
||||
/// Total amount of waiting time due to RPC server rate limiting
|
||||
/// (a subset of `elapsed_time`)
|
||||
pub rate_limited_time: Duration,
|
||||
}
|
||||
|
||||
/// A transport for RPC calls.
|
||||
///
|
||||
/// `RpcSender` implements the underlying transport of requests to, and
|
||||
/// responses from, a Solana node, and is used primarily by [`RpcClient`].
|
||||
///
|
||||
/// It is typically implemented by [`HttpSender`] in production, and
|
||||
/// [`MockSender`] in unit tests.
|
||||
///
|
||||
/// [`RpcClient`]: crate::rpc_client::RpcClient
|
||||
/// [`HttpSender`]: crate::http_sender::HttpSender
|
||||
/// [`MockSender`]: crate::mock_sender::MockSender
|
||||
pub trait RpcSender {
|
||||
fn send(&self, request: RpcRequest, params: serde_json::Value) -> Result<serde_json::Value>;
|
||||
fn get_transport_stats(&self) -> RpcTransportStats;
|
||||
}
|
||||
|
@@ -451,7 +451,7 @@ impl SyncClient for ThinClient {
|
||||
) -> TransportResult<Option<transaction::Result<()>>> {
|
||||
let status = self
|
||||
.rpc_client()
|
||||
.get_signature_status(signature)
|
||||
.get_signature_status(&signature)
|
||||
.map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
@@ -468,7 +468,7 @@ impl SyncClient for ThinClient {
|
||||
) -> TransportResult<Option<transaction::Result<()>>> {
|
||||
let status = self
|
||||
.rpc_client()
|
||||
.get_signature_status_with_commitment(signature, commitment_config)
|
||||
.get_signature_status_with_commitment(&signature, commitment_config)
|
||||
.map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
|
@@ -5,9 +5,7 @@ use crate::{
|
||||
};
|
||||
use bincode::serialize;
|
||||
use log::*;
|
||||
use solana_sdk::{
|
||||
clock::Slot, commitment_config::CommitmentConfig, pubkey::Pubkey, transaction::Transaction,
|
||||
};
|
||||
use solana_sdk::{clock::Slot, pubkey::Pubkey, transaction::Transaction};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet, VecDeque},
|
||||
net::{SocketAddr, UdpSocket},
|
||||
@@ -123,7 +121,7 @@ struct LeaderTpuCache {
|
||||
impl LeaderTpuCache {
|
||||
fn new(rpc_client: &RpcClient, first_slot: Slot) -> Self {
|
||||
let leaders = Self::fetch_slot_leaders(rpc_client, first_slot).unwrap_or_default();
|
||||
let leader_tpu_map = Self::fetch_cluster_tpu_sockets(rpc_client).unwrap_or_default();
|
||||
let leader_tpu_map = Self::fetch_cluster_tpu_sockets(&rpc_client).unwrap_or_default();
|
||||
Self {
|
||||
first_slot,
|
||||
leaders,
|
||||
@@ -244,7 +242,7 @@ struct LeaderTpuService {
|
||||
|
||||
impl LeaderTpuService {
|
||||
fn new(rpc_client: Arc<RpcClient>, websocket_url: &str, exit: Arc<AtomicBool>) -> Result<Self> {
|
||||
let start_slot = rpc_client.get_slot_with_commitment(CommitmentConfig::processed())?;
|
||||
let start_slot = rpc_client.get_max_shred_insert_slot()?;
|
||||
|
||||
let recent_slots = RecentLeaderSlots::new(start_slot);
|
||||
let leader_tpu_cache = Arc::new(RwLock::new(LeaderTpuCache::new(&rpc_client, start_slot)));
|
||||
|
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "solana-core"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.7.14"
|
||||
version = "1.6.28"
|
||||
homepage = "https://solana.com/"
|
||||
documentation = "https://docs.rs/solana-core"
|
||||
readme = "../README.md"
|
||||
@@ -22,12 +22,20 @@ bv = { version = "0.11.1", features = ["serde"] }
|
||||
bs58 = "0.3.1"
|
||||
byteorder = "1.3.4"
|
||||
chrono = { version = "0.4.11", features = ["serde"] }
|
||||
core_affinity = "0.5.10"
|
||||
crossbeam-channel = "0.4"
|
||||
dashmap = "4.0.2"
|
||||
ed25519-dalek = "=1.0.1"
|
||||
fs_extra = "1.2.0"
|
||||
flate2 = "1.0"
|
||||
indexmap = { version = "1.5", features = ["rayon"] }
|
||||
itertools = "0.9.0"
|
||||
jsonrpc-core = "18.0.0"
|
||||
jsonrpc-core-client = { version = "18.0.0", features = ["ipc", "ws"] }
|
||||
jsonrpc-derive = "18.0.0"
|
||||
jsonrpc-http-server = "18.0.0"
|
||||
jsonrpc-pubsub = "18.0.0"
|
||||
jsonrpc-ws-server = "18.0.0"
|
||||
libc = "0.2.81"
|
||||
log = "0.4.11"
|
||||
lru = "0.6.1"
|
||||
@@ -39,54 +47,55 @@ rand_chacha = "0.2.2"
|
||||
rand_core = "0.6.2"
|
||||
raptorq = "1.4.2"
|
||||
rayon = "1.5.0"
|
||||
regex = "1.3.9"
|
||||
retain_mut = "0.1.2"
|
||||
serde = "1.0.122"
|
||||
serde_bytes = "0.11"
|
||||
serde_derive = "1.0.103"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.7.14" }
|
||||
solana-banks-server = { path = "../banks-server", version = "=1.7.14" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.7.14" }
|
||||
solana-client = { path = "../client", version = "=1.7.14" }
|
||||
solana-gossip = { path = "../gossip", version = "=1.7.14" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.7.14" }
|
||||
solana-logger = { path = "../logger", version = "=1.7.14" }
|
||||
solana-merkle-tree = { path = "../merkle-tree", version = "=1.7.14" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.7.14" }
|
||||
solana-measure = { path = "../measure", version = "=1.7.14" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.7.14" }
|
||||
solana-perf = { path = "../perf", version = "=1.7.14" }
|
||||
solana-poh = { path = "../poh", version = "=1.7.14" }
|
||||
solana-program-test = { path = "../program-test", version = "=1.7.14" }
|
||||
solana-rpc = { path = "../rpc", version = "=1.7.14" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.7.14" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.7.14" }
|
||||
solana-frozen-abi = { path = "../frozen-abi", version = "=1.7.14" }
|
||||
solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "=1.7.14" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.7.14" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.7.14" }
|
||||
solana-version = { path = "../version", version = "=1.7.14" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.7.14" }
|
||||
spl-token-v2-0 = { package = "spl-token", version = "=3.2.0", features = ["no-entrypoint"] }
|
||||
serde_json = "1.0.56"
|
||||
soketto = "0.6"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.28" }
|
||||
solana-banks-server = { path = "../banks-server", version = "=1.6.28" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.28" }
|
||||
solana-client = { path = "../client", version = "=1.6.28" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.28" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.6.28" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.28" }
|
||||
solana-merkle-tree = { path = "../merkle-tree", version = "=1.6.28" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.28" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.28" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.28" }
|
||||
solana-perf = { path = "../perf", version = "=1.6.28" }
|
||||
solana-program-test = { path = "../program-test", version = "=1.6.28" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.28" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.28" }
|
||||
solana-frozen-abi = { path = "../frozen-abi", version = "=1.6.28" }
|
||||
solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "=1.6.28" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.28" }
|
||||
solana-storage-bigtable = { path = "../storage-bigtable", version = "=1.6.28" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.6.28" }
|
||||
solana-sys-tuner = { path = "../sys-tuner", version = "=1.6.28" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.28" }
|
||||
solana-version = { path = "../version", version = "=1.6.28" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.28" }
|
||||
spl-token-v2-0 = { package = "spl-token", version = "=3.1.1", features = ["no-entrypoint"] }
|
||||
tempfile = "3.1.0"
|
||||
stream-cancel = "0.8.1"
|
||||
thiserror = "1.0"
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.7.14" }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tokio-util = { version = "0.6", features = ["codec", "compat"] }
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.6.28" }
|
||||
trees = "0.2.1"
|
||||
|
||||
[dev-dependencies]
|
||||
jsonrpc-core = "18.0.0"
|
||||
jsonrpc-core-client = { version = "18.0.0", features = ["ipc", "ws"] }
|
||||
jsonrpc-derive = "18.0.0"
|
||||
jsonrpc-pubsub = "18.0.0"
|
||||
matches = "0.1.6"
|
||||
num_cpus = "1.13.0"
|
||||
reqwest = { version = "0.11.2", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
||||
serde_json = "1.0.56"
|
||||
serial_test = "0.4.0"
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.7.14" }
|
||||
solana-version = { path = "../version", version = "=1.7.14" }
|
||||
symlink = "0.1.0"
|
||||
systemstat = "0.1.5"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
|
||||
[build-dependencies]
|
||||
rustc_version = "0.2"
|
||||
@@ -98,7 +107,13 @@ name = "banking_stage"
|
||||
name = "blockstore"
|
||||
|
||||
[[bench]]
|
||||
name = "cluster_info"
|
||||
name = "crds"
|
||||
|
||||
[[bench]]
|
||||
name = "crds_gossip_pull"
|
||||
|
||||
[[bench]]
|
||||
name = "crds_shards"
|
||||
|
||||
[[bench]]
|
||||
name = "gen_keys"
|
||||
@@ -106,8 +121,14 @@ name = "gen_keys"
|
||||
[[bench]]
|
||||
name = "sigverify_stage"
|
||||
|
||||
[[bench]]
|
||||
name = "poh"
|
||||
|
||||
[[bench]]
|
||||
name = "retransmit_stage"
|
||||
|
||||
[[bench]]
|
||||
name = "cluster_info"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -7,16 +7,16 @@ use crossbeam_channel::unbounded;
|
||||
use log::*;
|
||||
use rand::{thread_rng, Rng};
|
||||
use rayon::prelude::*;
|
||||
use solana_core::banking_stage::{BankingStage, BankingStageStats};
|
||||
use solana_gossip::cluster_info::ClusterInfo;
|
||||
use solana_gossip::cluster_info::Node;
|
||||
use solana_core::banking_stage::{create_test_recorder, BankingStage, BankingStageStats};
|
||||
use solana_core::cluster_info::ClusterInfo;
|
||||
use solana_core::cluster_info::Node;
|
||||
use solana_core::poh_recorder::WorkingBankEntry;
|
||||
use solana_ledger::blockstore_processor::process_entries;
|
||||
use solana_ledger::entry::{next_hash, Entry};
|
||||
use solana_ledger::genesis_utils::{create_genesis_config, GenesisConfigInfo};
|
||||
use solana_ledger::{blockstore::Blockstore, get_tmp_ledger_path};
|
||||
use solana_perf::packet::to_packets_chunked;
|
||||
use solana_perf::test_tx::test_tx;
|
||||
use solana_poh::poh_recorder::{create_test_recorder, WorkingBankEntry};
|
||||
use solana_runtime::bank::Bank;
|
||||
use solana_sdk::genesis_config::GenesisConfig;
|
||||
use solana_sdk::hash::Hash;
|
||||
@@ -29,7 +29,6 @@ use solana_sdk::system_instruction;
|
||||
use solana_sdk::system_transaction;
|
||||
use solana_sdk::timing::{duration_as_us, timestamp};
|
||||
use solana_sdk::transaction::Transaction;
|
||||
use solana_streamer::socket::SocketAddrSpace;
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::mpsc::Receiver;
|
||||
@@ -108,7 +107,7 @@ fn make_accounts_txs(txes: usize, mint_keypair: &Keypair, hash: Hash) -> Vec<Tra
|
||||
.into_par_iter()
|
||||
.map(|_| {
|
||||
let mut new = dummy.clone();
|
||||
let sig: Vec<_> = (0..64).map(|_| thread_rng().gen::<u8>()).collect();
|
||||
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
|
||||
new.message.account_keys[0] = pubkey::new_rand();
|
||||
new.message.account_keys[1] = pubkey::new_rand();
|
||||
new.signatures = vec![Signature::new(&sig[0..64])];
|
||||
@@ -158,7 +157,6 @@ fn bench_banking(bencher: &mut Bencher, tx_type: TransactionType) {
|
||||
genesis_config.ticks_per_slot = 10_000;
|
||||
|
||||
let (verified_sender, verified_receiver) = unbounded();
|
||||
let (tpu_vote_sender, tpu_vote_receiver) = unbounded();
|
||||
let (vote_sender, vote_receiver) = unbounded();
|
||||
let mut bank = Bank::new(&genesis_config);
|
||||
// Allow arbitrary transaction processing time for the purposes of this bench
|
||||
@@ -185,7 +183,7 @@ fn bench_banking(bencher: &mut Bencher, tx_type: TransactionType) {
|
||||
});
|
||||
//sanity check, make sure all the transactions can execute sequentially
|
||||
transactions.iter().for_each(|tx| {
|
||||
let res = bank.process_transaction(tx);
|
||||
let res = bank.process_transaction(&tx);
|
||||
assert!(res.is_ok(), "sanity test transactions");
|
||||
});
|
||||
bank.clear_signatures();
|
||||
@@ -203,18 +201,13 @@ fn bench_banking(bencher: &mut Bencher, tx_type: TransactionType) {
|
||||
);
|
||||
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()),
|
||||
SocketAddrSpace::Unspecified,
|
||||
);
|
||||
let cluster_info = ClusterInfo::new_with_invalid_keypair(Node::new_localhost().info);
|
||||
let cluster_info = Arc::new(cluster_info);
|
||||
let (s, _r) = unbounded();
|
||||
let _banking_stage = BankingStage::new(
|
||||
&cluster_info,
|
||||
&poh_recorder,
|
||||
verified_receiver,
|
||||
tpu_vote_receiver,
|
||||
vote_receiver,
|
||||
None,
|
||||
s,
|
||||
@@ -261,7 +254,6 @@ fn bench_banking(bencher: &mut Bencher, tx_type: TransactionType) {
|
||||
start += chunk_len;
|
||||
start %= verified.len();
|
||||
});
|
||||
drop(tpu_vote_sender);
|
||||
drop(vote_sender);
|
||||
exit.store(true, Ordering::Relaxed);
|
||||
poh_service.join().unwrap();
|
||||
|
@@ -2,54 +2,29 @@
|
||||
|
||||
extern crate test;
|
||||
|
||||
use {
|
||||
rand::{thread_rng, Rng},
|
||||
solana_core::{
|
||||
broadcast_stage::{
|
||||
broadcast_metrics::TransmitShredsStats, broadcast_shreds, BroadcastStage,
|
||||
},
|
||||
cluster_nodes::ClusterNodesCache,
|
||||
},
|
||||
solana_gossip::{
|
||||
cluster_info::{ClusterInfo, Node},
|
||||
contact_info::ContactInfo,
|
||||
},
|
||||
solana_ledger::{
|
||||
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
||||
shred::Shred,
|
||||
},
|
||||
solana_runtime::{bank::Bank, bank_forks::BankForks},
|
||||
solana_sdk::{
|
||||
pubkey,
|
||||
signature::Keypair,
|
||||
timing::{timestamp, AtomicInterval},
|
||||
},
|
||||
solana_streamer::socket::SocketAddrSpace,
|
||||
std::{
|
||||
collections::HashMap,
|
||||
net::UdpSocket,
|
||||
sync::{Arc, RwLock},
|
||||
time::Duration,
|
||||
},
|
||||
test::Bencher,
|
||||
use rand::{thread_rng, Rng};
|
||||
use solana_core::broadcast_stage::broadcast_metrics::TransmitShredsStats;
|
||||
use solana_core::broadcast_stage::{broadcast_shreds, get_broadcast_peers};
|
||||
use solana_core::cluster_info::{ClusterInfo, Node};
|
||||
use solana_core::contact_info::ContactInfo;
|
||||
use solana_ledger::shred::Shred;
|
||||
use solana_sdk::pubkey;
|
||||
use solana_sdk::timing::timestamp;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
net::UdpSocket,
|
||||
sync::{atomic::AtomicU64, Arc},
|
||||
};
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn broadcast_shreds_bench(bencher: &mut Bencher) {
|
||||
solana_logger::setup();
|
||||
let leader_pubkey = pubkey::new_rand();
|
||||
let leader_info = Node::new_localhost_with_pubkey(&leader_pubkey);
|
||||
let cluster_info = ClusterInfo::new(
|
||||
leader_info.info,
|
||||
Arc::new(Keypair::new()),
|
||||
SocketAddrSpace::Unspecified,
|
||||
);
|
||||
let cluster_info = ClusterInfo::new_with_invalid_keypair(leader_info.info);
|
||||
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||
|
||||
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
|
||||
let bank = Bank::new(&genesis_config);
|
||||
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
||||
|
||||
const NUM_SHREDS: usize = 32;
|
||||
let shreds = vec![Shred::new_empty_data_shred(); NUM_SHREDS];
|
||||
let mut stakes = HashMap::new();
|
||||
@@ -61,23 +36,18 @@ fn broadcast_shreds_bench(bencher: &mut Bencher) {
|
||||
stakes.insert(id, thread_rng().gen_range(1, NUM_PEERS) as u64);
|
||||
}
|
||||
let cluster_info = Arc::new(cluster_info);
|
||||
let cluster_nodes_cache = ClusterNodesCache::<BroadcastStage>::new(
|
||||
8, // cap
|
||||
Duration::from_secs(5), // ttl
|
||||
);
|
||||
let (peers, peers_and_stakes) = get_broadcast_peers(&cluster_info, Some(&stakes));
|
||||
let shreds = Arc::new(shreds);
|
||||
let last_datapoint = Arc::new(AtomicInterval::default());
|
||||
let last_datapoint = Arc::new(AtomicU64::new(0));
|
||||
bencher.iter(move || {
|
||||
let shreds = shreds.clone();
|
||||
broadcast_shreds(
|
||||
&socket,
|
||||
&shreds,
|
||||
&cluster_nodes_cache,
|
||||
&peers_and_stakes,
|
||||
&peers,
|
||||
&last_datapoint,
|
||||
&mut TransmitShredsStats::default(),
|
||||
&SocketAddrSpace::Unspecified,
|
||||
&cluster_info,
|
||||
&bank_forks,
|
||||
)
|
||||
.unwrap();
|
||||
});
|
||||
|
@@ -24,10 +24,10 @@ fn bench_save_tower(bench: &mut Bencher) {
|
||||
let heaviest_bank = BankForks::new(Bank::default()).working_bank();
|
||||
let tower = Tower::new(
|
||||
&node_keypair.pubkey(),
|
||||
vote_account_pubkey,
|
||||
&vote_account_pubkey,
|
||||
0,
|
||||
&heaviest_bank,
|
||||
path,
|
||||
&path,
|
||||
);
|
||||
|
||||
bench.iter(move || {
|
||||
|
@@ -2,16 +2,14 @@
|
||||
|
||||
extern crate test;
|
||||
|
||||
use {
|
||||
rand::{thread_rng, Rng},
|
||||
rayon::ThreadPoolBuilder,
|
||||
solana_gossip::{
|
||||
crds::Crds, crds_gossip_pull::CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS, crds_value::CrdsValue,
|
||||
},
|
||||
solana_sdk::pubkey::Pubkey,
|
||||
std::collections::HashMap,
|
||||
test::Bencher,
|
||||
};
|
||||
use rand::{thread_rng, Rng};
|
||||
use rayon::ThreadPoolBuilder;
|
||||
use solana_core::crds::Crds;
|
||||
use solana_core::crds_gossip_pull::CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS;
|
||||
use solana_core::crds_value::CrdsValue;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use std::collections::HashMap;
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_find_old_labels(bencher: &mut Bencher) {
|
@@ -2,18 +2,14 @@
|
||||
|
||||
extern crate test;
|
||||
|
||||
use {
|
||||
rand::{thread_rng, Rng},
|
||||
rayon::ThreadPoolBuilder,
|
||||
solana_gossip::{
|
||||
cluster_info::MAX_BLOOM_SIZE,
|
||||
crds::Crds,
|
||||
crds_gossip_pull::{CrdsFilter, CrdsGossipPull},
|
||||
crds_value::CrdsValue,
|
||||
},
|
||||
solana_sdk::hash,
|
||||
test::Bencher,
|
||||
};
|
||||
use rand::{thread_rng, Rng};
|
||||
use rayon::ThreadPoolBuilder;
|
||||
use solana_core::cluster_info::MAX_BLOOM_SIZE;
|
||||
use solana_core::crds::Crds;
|
||||
use solana_core::crds_gossip_pull::{CrdsFilter, CrdsGossipPull};
|
||||
use solana_core::crds_value::CrdsValue;
|
||||
use solana_sdk::hash;
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_hash_as_u64(bencher: &mut Bencher) {
|
@@ -2,17 +2,15 @@
|
||||
|
||||
extern crate test;
|
||||
|
||||
use {
|
||||
rand::{thread_rng, Rng},
|
||||
solana_gossip::{
|
||||
crds::{Crds, VersionedCrdsValue},
|
||||
crds_shards::CrdsShards,
|
||||
crds_value::CrdsValue,
|
||||
},
|
||||
solana_sdk::timing::timestamp,
|
||||
std::iter::repeat_with,
|
||||
test::Bencher,
|
||||
use rand::{thread_rng, Rng};
|
||||
use solana_core::{
|
||||
crds::{Crds, VersionedCrdsValue},
|
||||
crds_shards::CrdsShards,
|
||||
crds_value::CrdsValue,
|
||||
};
|
||||
use solana_sdk::timing::timestamp;
|
||||
use std::iter::repeat_with;
|
||||
use test::Bencher;
|
||||
|
||||
const CRDS_SHARDS_BITS: u32 = 8;
|
||||
|
@@ -3,16 +3,12 @@
|
||||
#![feature(test)]
|
||||
extern crate test;
|
||||
|
||||
use {
|
||||
solana_ledger::poh::Poh,
|
||||
solana_poh::poh_service::DEFAULT_HASHES_PER_BATCH,
|
||||
solana_sdk::hash::Hash,
|
||||
std::sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc, Mutex,
|
||||
},
|
||||
test::Bencher,
|
||||
};
|
||||
use solana_core::poh_service::DEFAULT_HASHES_PER_BATCH;
|
||||
use solana_ledger::poh::Poh;
|
||||
use solana_sdk::hash::Hash;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use test::Bencher;
|
||||
|
||||
const NUM_HASHES: u64 = 30_000; // Should require ~10ms on a 2017 MacBook Pro
|
||||
|
@@ -1,15 +1,11 @@
|
||||
#![feature(test)]
|
||||
extern crate test;
|
||||
|
||||
use {
|
||||
solana_ledger::entry::{next_entry_mut, Entry, EntrySlice},
|
||||
solana_sdk::{
|
||||
hash::{hash, Hash},
|
||||
signature::{Keypair, Signer},
|
||||
system_transaction,
|
||||
},
|
||||
test::Bencher,
|
||||
};
|
||||
use solana_ledger::entry::{next_entry_mut, Entry, EntrySlice};
|
||||
use solana_sdk::hash::{hash, Hash};
|
||||
use solana_sdk::signature::{Keypair, Signer};
|
||||
use solana_sdk::system_transaction;
|
||||
use test::Bencher;
|
||||
|
||||
const NUM_HASHES: u64 = 400;
|
||||
const NUM_ENTRIES: usize = 800;
|
||||
@@ -18,7 +14,7 @@ const NUM_ENTRIES: usize = 800;
|
||||
fn bench_poh_verify_ticks(bencher: &mut Bencher) {
|
||||
solana_logger::setup();
|
||||
let zero = Hash::default();
|
||||
let start_hash = hash(zero.as_ref());
|
||||
let start_hash = hash(&zero.as_ref());
|
||||
let mut cur_hash = start_hash;
|
||||
|
||||
let mut ticks: Vec<Entry> = Vec::with_capacity(NUM_ENTRIES);
|
||||
@@ -34,7 +30,7 @@ fn bench_poh_verify_ticks(bencher: &mut Bencher) {
|
||||
#[bench]
|
||||
fn bench_poh_verify_transaction_entries(bencher: &mut Bencher) {
|
||||
let zero = Hash::default();
|
||||
let start_hash = hash(zero.as_ref());
|
||||
let start_hash = hash(&zero.as_ref());
|
||||
let mut cur_hash = start_hash;
|
||||
|
||||
let keypair1 = Keypair::new();
|
@@ -3,62 +3,43 @@
|
||||
extern crate solana_core;
|
||||
extern crate test;
|
||||
|
||||
use {
|
||||
log::*,
|
||||
solana_core::retransmit_stage::retransmitter,
|
||||
solana_gossip::{
|
||||
cluster_info::{ClusterInfo, Node},
|
||||
contact_info::ContactInfo,
|
||||
},
|
||||
solana_ledger::{
|
||||
entry::Entry,
|
||||
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
||||
leader_schedule_cache::LeaderScheduleCache,
|
||||
shred::Shredder,
|
||||
},
|
||||
solana_measure::measure::Measure,
|
||||
solana_runtime::{bank::Bank, bank_forks::BankForks},
|
||||
solana_sdk::{
|
||||
hash::Hash,
|
||||
pubkey::Pubkey,
|
||||
signature::{Keypair, Signer},
|
||||
system_transaction,
|
||||
timing::timestamp,
|
||||
},
|
||||
solana_streamer::socket::SocketAddrSpace,
|
||||
std::{
|
||||
net::UdpSocket,
|
||||
sync::{
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
mpsc::channel,
|
||||
Arc, RwLock,
|
||||
},
|
||||
thread::{sleep, Builder},
|
||||
time::Duration,
|
||||
},
|
||||
test::Bencher,
|
||||
};
|
||||
use log::*;
|
||||
use solana_core::cluster_info::{ClusterInfo, Node};
|
||||
use solana_core::contact_info::ContactInfo;
|
||||
use solana_core::max_slots::MaxSlots;
|
||||
use solana_core::retransmit_stage::retransmitter;
|
||||
use solana_ledger::entry::Entry;
|
||||
use solana_ledger::genesis_utils::{create_genesis_config, GenesisConfigInfo};
|
||||
use solana_ledger::leader_schedule_cache::LeaderScheduleCache;
|
||||
use solana_ledger::shred::Shredder;
|
||||
use solana_measure::measure::Measure;
|
||||
use solana_perf::packet::{Packet, Packets};
|
||||
use solana_runtime::bank::Bank;
|
||||
use solana_runtime::bank_forks::BankForks;
|
||||
use solana_sdk::hash::Hash;
|
||||
use solana_sdk::pubkey;
|
||||
use solana_sdk::signature::{Keypair, Signer};
|
||||
use solana_sdk::system_transaction;
|
||||
use solana_sdk::timing::timestamp;
|
||||
use std::net::UdpSocket;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::mpsc::channel;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::thread::sleep;
|
||||
use std::thread::Builder;
|
||||
use std::time::Duration;
|
||||
use test::Bencher;
|
||||
|
||||
// TODO: The benchmark is ignored as it currently may indefinitely block.
|
||||
// The code incorrectly expects that the node receiving the shred on tvu socket
|
||||
// retransmits that to other nodes in its neighborhood. But that is no longer
|
||||
// the case since https://github.com/solana-labs/solana/pull/17716.
|
||||
// So depending on shred seed, peers may not receive packets and the receive
|
||||
// threads loop indefinitely.
|
||||
#[ignore]
|
||||
#[bench]
|
||||
#[allow(clippy::same_item_push)]
|
||||
fn bench_retransmitter(bencher: &mut Bencher) {
|
||||
solana_logger::setup();
|
||||
let cluster_info = ClusterInfo::new(
|
||||
Node::new_localhost().info,
|
||||
Arc::new(Keypair::new()),
|
||||
SocketAddrSpace::Unspecified,
|
||||
);
|
||||
let cluster_info = ClusterInfo::new_with_invalid_keypair(Node::new_localhost().info);
|
||||
const NUM_PEERS: usize = 4;
|
||||
let mut peer_sockets = Vec::new();
|
||||
for _ in 0..NUM_PEERS {
|
||||
let id = Pubkey::new_unique();
|
||||
let id = pubkey::new_rand();
|
||||
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||
let mut contact_info = ContactInfo::new_localhost(&id, timestamp());
|
||||
contact_info.tvu = socket.local_addr().unwrap();
|
||||
@@ -77,7 +58,8 @@ fn bench_retransmitter(bencher: &mut Bencher) {
|
||||
let bank_forks = BankForks::new(bank0);
|
||||
let bank = bank_forks.working_bank();
|
||||
let bank_forks = Arc::new(RwLock::new(bank_forks));
|
||||
let (shreds_sender, shreds_receiver) = channel();
|
||||
let (packet_sender, packet_receiver) = channel();
|
||||
let packet_receiver = Arc::new(Mutex::new(packet_receiver));
|
||||
const NUM_THREADS: usize = 2;
|
||||
let sockets = (0..NUM_THREADS)
|
||||
.map(|_| UdpSocket::bind("0.0.0.0:0").unwrap())
|
||||
@@ -107,10 +89,10 @@ fn bench_retransmitter(bencher: &mut Bencher) {
|
||||
let retransmitter_handles = retransmitter(
|
||||
Arc::new(sockets),
|
||||
bank_forks,
|
||||
leader_schedule_cache,
|
||||
&leader_schedule_cache,
|
||||
cluster_info,
|
||||
shreds_receiver,
|
||||
Arc::default(), // solana_rpc::max_slots::MaxSlots
|
||||
packet_receiver,
|
||||
&Arc::new(MaxSlots::default()),
|
||||
None,
|
||||
);
|
||||
|
||||
@@ -148,7 +130,9 @@ fn bench_retransmitter(bencher: &mut Bencher) {
|
||||
shred.set_index(index);
|
||||
index += 1;
|
||||
index %= 200;
|
||||
let _ = shreds_sender.send(vec![shred.clone()]);
|
||||
let mut p = Packet::default();
|
||||
shred.copy_to_packet(&mut p);
|
||||
let _ = packet_sender.send(Packets::new(vec![p]));
|
||||
}
|
||||
slot += 1;
|
||||
|
||||
@@ -164,5 +148,7 @@ fn bench_retransmitter(bencher: &mut Bencher) {
|
||||
total.store(0, Ordering::Relaxed);
|
||||
});
|
||||
|
||||
retransmitter_handles.join().unwrap();
|
||||
for t in retransmitter_handles {
|
||||
t.join().unwrap();
|
||||
}
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@ use raptorq::{Decoder, Encoder};
|
||||
use solana_ledger::entry::{create_ticks, Entry};
|
||||
use solana_ledger::shred::{
|
||||
max_entries_per_n_shred, max_ticks_per_n_shreds, ProcessShredsStats, Shred, Shredder,
|
||||
MAX_DATA_SHREDS_PER_FEC_BLOCK, SHRED_PAYLOAD_SIZE, SIZE_OF_CODING_SHRED_HEADERS,
|
||||
MAX_DATA_SHREDS_PER_FEC_BLOCK, SHRED_PAYLOAD_SIZE, SIZE_OF_DATA_SHRED_IGNORED_TAIL,
|
||||
SIZE_OF_DATA_SHRED_PAYLOAD,
|
||||
};
|
||||
use solana_perf::test_tx;
|
||||
@@ -55,7 +55,7 @@ fn make_shreds(num_shreds: usize) -> Vec<Shred> {
|
||||
|
||||
fn make_concatenated_shreds(num_shreds: usize) -> Vec<u8> {
|
||||
let data_shreds = make_shreds(num_shreds);
|
||||
let valid_shred_data_len = (SHRED_PAYLOAD_SIZE - SIZE_OF_CODING_SHRED_HEADERS) as usize;
|
||||
let valid_shred_data_len = (SHRED_PAYLOAD_SIZE - SIZE_OF_DATA_SHRED_IGNORED_TAIL) as usize;
|
||||
let mut data: Vec<u8> = vec![0; num_shreds * valid_shred_data_len];
|
||||
for (i, shred) in (data_shreds[0..num_shreds]).iter().enumerate() {
|
||||
data[i * valid_shred_data_len..(i + 1) * valid_shred_data_len]
|
||||
@@ -163,7 +163,7 @@ fn bench_shredder_decoding(bencher: &mut Bencher) {
|
||||
fn bench_shredder_coding_raptorq(bencher: &mut Bencher) {
|
||||
let symbol_count = MAX_DATA_SHREDS_PER_FEC_BLOCK;
|
||||
let data = make_concatenated_shreds(symbol_count as usize);
|
||||
let valid_shred_data_len = (SHRED_PAYLOAD_SIZE - SIZE_OF_CODING_SHRED_HEADERS) as usize;
|
||||
let valid_shred_data_len = (SHRED_PAYLOAD_SIZE - SIZE_OF_DATA_SHRED_IGNORED_TAIL) as usize;
|
||||
bencher.iter(|| {
|
||||
let encoder = Encoder::with_defaults(&data, valid_shred_data_len as u16);
|
||||
encoder.get_encoded_packets(symbol_count);
|
||||
@@ -174,7 +174,7 @@ fn bench_shredder_coding_raptorq(bencher: &mut Bencher) {
|
||||
fn bench_shredder_decoding_raptorq(bencher: &mut Bencher) {
|
||||
let symbol_count = MAX_DATA_SHREDS_PER_FEC_BLOCK;
|
||||
let data = make_concatenated_shreds(symbol_count as usize);
|
||||
let valid_shred_data_len = (SHRED_PAYLOAD_SIZE - SIZE_OF_CODING_SHRED_HEADERS) as usize;
|
||||
let valid_shred_data_len = (SHRED_PAYLOAD_SIZE - SIZE_OF_DATA_SHRED_IGNORED_TAIL) as usize;
|
||||
let encoder = Encoder::with_defaults(&data, valid_shred_data_len as u16);
|
||||
let mut packets = encoder.get_encoded_packets(symbol_count as u32);
|
||||
packets.shuffle(&mut rand::thread_rng());
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user